From a68fb2d8219f6bccc573009600e9f23e89226a5e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 20:04:16 +0200 Subject: Adding upstream version 1:10.6.11. Signed-off-by: Daniel Baumann --- storage/connect/.gitignore | 264 + storage/connect/ApacheInterface.java | 61 + storage/connect/CMakeLists.txt | 458 + storage/connect/Client.java | 200 + storage/connect/Client2.java | 130 + storage/connect/Client3.java | 154 + storage/connect/JdbcInterface.java | 834 + storage/connect/MariadbInterface.java | 69 + storage/connect/Mongo2Interface.java | 531 + storage/connect/Mongo3Interface.java | 618 + storage/connect/MysqlInterface.java | 69 + storage/connect/OracleInterface.java | 69 + storage/connect/PostgresqlInterface.java | 70 + storage/connect/TestInsert2.java | 131 + storage/connect/TestInsert3.java | 131 + storage/connect/array.cpp | 1151 + storage/connect/array.h | 131 + storage/connect/blkfil.cpp | 1075 + storage/connect/blkfil.h | 295 + storage/connect/block.h | 61 + storage/connect/bson.cpp | 1795 ++ storage/connect/bson.h | 207 + storage/connect/bsonudf.cpp | 6221 ++++ storage/connect/bsonudf.h | 410 + storage/connect/catalog.h | 105 + storage/connect/checklvl.h | 51 + storage/connect/cmgfam.cpp | 315 + storage/connect/cmgfam.h | 68 + storage/connect/cmgoconn.cpp | 1120 + storage/connect/cmgoconn.h | 121 + storage/connect/colblk.cpp | 414 + storage/connect/colblk.h | 232 + storage/connect/connect.cc | 973 + storage/connect/connect.h | 80 + storage/connect/csort.cpp | 966 + storage/connect/csort.h | 104 + storage/connect/domdoc.cpp | 755 + storage/connect/domdoc.h | 146 + storage/connect/encas.h | 320 + storage/connect/engmsg.h | 326 + storage/connect/enids.h | 46 + storage/connect/filamap.cpp | 788 + storage/connect/filamap.h | 120 + storage/connect/filamdbf.cpp | 1203 + storage/connect/filamdbf.h | 108 + storage/connect/filamfix.cpp | 1539 + storage/connect/filamfix.h | 93 + storage/connect/filamgz.cpp | 1427 + storage/connect/filamgz.h | 170 + storage/connect/filamtxt.cpp | 2119 ++ storage/connect/filamtxt.h | 254 + storage/connect/filamvct.cpp | 4327 +++ storage/connect/filamvct.h | 252 + storage/connect/filamzip.cpp | 1454 + storage/connect/filamzip.h | 232 + storage/connect/filter.cpp | 1753 ++ storage/connect/filter.h | 178 + storage/connect/fmdlex.c | 1540 + storage/connect/global.h | 232 + storage/connect/ha_connect.cc | 7546 +++++ storage/connect/ha_connect.h | 579 + storage/connect/inihandl.cpp | 1405 + storage/connect/inihandl.h | 55 + storage/connect/ioapi.c | 247 + storage/connect/ioapi.h | 210 + storage/connect/javaconn.cpp | 613 + storage/connect/javaconn.h | 130 + storage/connect/jdbccat.h | 35 + storage/connect/jdbconn.cpp | 1691 ++ storage/connect/jdbconn.h | 92 + storage/connect/jmgfam.cpp | 390 + storage/connect/jmgfam.h | 82 + storage/connect/jmgoconn.cpp | 883 + storage/connect/jmgoconn.h | 116 + storage/connect/json.cpp | 2063 ++ storage/connect/json.h | 364 + storage/connect/jsonudf.cpp | 6646 +++++ storage/connect/jsonudf.h | 411 + storage/connect/libdoc.cpp | 1250 + storage/connect/libdoc.h | 6 + storage/connect/macutil.cpp | 318 + storage/connect/macutil.h | 36 + storage/connect/maputil.cpp | 200 + storage/connect/maputil.h | 21 + storage/connect/messages.h | 5 + storage/connect/mini-global.h | 33 + storage/connect/mongo.cpp | 451 + storage/connect/mongo.h | 91 + storage/connect/msgid.h | 326 + storage/connect/mycat.cc | 583 + storage/connect/mycat.h | 119 + storage/connect/myconn.cpp | 1096 + storage/connect/myconn.h | 105 + storage/connect/mysql-test/connect/disabled.def | 27 + storage/connect/mysql-test/connect/my.cnf | 17 + storage/connect/mysql-test/connect/r/alter.result | 274 + .../mysql-test/connect/r/alter_engine.result | 11 + .../connect/mysql-test/connect/r/alter_xml.result | 84 + .../connect/mysql-test/connect/r/alter_xml2.result | 84 + storage/connect/mysql-test/connect/r/bin.result | 99 + storage/connect/mysql-test/connect/r/bson.result | 541 + .../mysql-test/connect/r/bson_java_2.result | 385 + .../mysql-test/connect/r/bson_java_3.result | 385 + .../mysql-test/connect/r/bson_mongo_c.result | 385 + .../connect/mysql-test/connect/r/bson_udf.result | 685 + storage/connect/mysql-test/connect/r/csv.result | 221 + storage/connect/mysql-test/connect/r/datest.result | 59 + storage/connect/mysql-test/connect/r/dbf.result | 649 + storage/connect/mysql-test/connect/r/dir.result | 32 + .../mysql-test/connect/r/drop-open-error.result | 15 + storage/connect/mysql-test/connect/r/endian.result | 105 + storage/connect/mysql-test/connect/r/fix.result | 131 + storage/connect/mysql-test/connect/r/fmt.result | 68 + .../connect/mysql-test/connect/r/general.result | 32 + storage/connect/mysql-test/connect/r/grant.result | 604 + storage/connect/mysql-test/connect/r/grant2.result | 770 + storage/connect/mysql-test/connect/r/grant3.result | 5 + storage/connect/mysql-test/connect/r/index.result | 141 + .../mysql-test/connect/r/infoschema-9739.result | 8 + .../mysql-test/connect/r/infoschema2-9739.result | 8 + storage/connect/mysql-test/connect/r/ini.result | 279 + .../connect/mysql-test/connect/r/ini_grant.result | 89 + storage/connect/mysql-test/connect/r/jdbc.result | 284 + .../connect/mysql-test/connect/r/jdbc_new.result | 234 + .../mysql-test/connect/r/jdbc_oracle.result | 76 + .../mysql-test/connect/r/jdbc_postgresql.result | 74 + storage/connect/mysql-test/connect/r/json.result | 541 + .../mysql-test/connect/r/json_java_2.result | 385 + .../mysql-test/connect/r/json_java_3.result | 385 + .../mysql-test/connect/r/json_mongo_c.result | 385 + .../connect/mysql-test/connect/r/json_udf.result | 651 + .../mysql-test/connect/r/json_udf_bin.result | 587 + storage/connect/mysql-test/connect/r/misc.result | 54 + .../connect/mysql-test/connect/r/mongo_c.result | 381 + .../mysql-test/connect/r/mongo_java_2.result | 381 + .../mysql-test/connect/r/mongo_java_3.result | 381 + storage/connect/mysql-test/connect/r/mrr.result | 117 + storage/connect/mysql-test/connect/r/mul.result | 57 + .../connect/mysql-test/connect/r/mul_new.result | 136 + storage/connect/mysql-test/connect/r/mysql.result | 330 + .../mysql-test/connect/r/mysql_discovery.result | 45 + .../connect/mysql-test/connect/r/mysql_exec.result | 76 + .../mysql-test/connect/r/mysql_grant.result | 73 + .../mysql-test/connect/r/mysql_index.result | 436 + .../connect/mysql-test/connect/r/mysql_new.result | 237 + storage/connect/mysql-test/connect/r/null.result | 134 + storage/connect/mysql-test/connect/r/occur.result | 255 + storage/connect/mysql-test/connect/r/odbc.result | 47 + .../mysql-test/connect/r/odbc_firebird.result | 110 + .../mysql-test/connect/r/odbc_oracle.result | 237 + .../mysql-test/connect/r/odbc_postgresql.result | 321 + .../mysql-test/connect/r/odbc_sqlite3.result | 2463 ++ .../mysql-test/connect/r/odbc_sqlite3_grant.result | 86 + .../connect/mysql-test/connect/r/odbc_xls.result | 26 + .../connect/mysql-test/connect/r/part_file.result | 343 + .../connect/mysql-test/connect/r/part_table.result | 222 + storage/connect/mysql-test/connect/r/pivot.result | 251 + storage/connect/mysql-test/connect/r/rest.result | 19 + .../mysql-test/connect/r/secure_file_priv.result | 8 + storage/connect/mysql-test/connect/r/tbl.result | 143 + .../connect/mysql-test/connect/r/tbl_thread.result | 165 + .../connect/mysql-test/connect/r/temporary.result | 6 + .../connect/mysql-test/connect/r/type_inet6.result | 15 + .../connect/mysql-test/connect/r/unsigned.result | 61 + storage/connect/mysql-test/connect/r/upd.result | 1629 + storage/connect/mysql-test/connect/r/updelx.result | 2570 ++ .../connect/mysql-test/connect/r/updelx2.result | 133 + storage/connect/mysql-test/connect/r/vcol.result | 29 + storage/connect/mysql-test/connect/r/vec.result | 138 + storage/connect/mysql-test/connect/r/xcol.result | 117 + storage/connect/mysql-test/connect/r/xml.result | 392 + storage/connect/mysql-test/connect/r/xml2.result | 398 + .../connect/mysql-test/connect/r/xml2_grant.result | 105 + .../connect/mysql-test/connect/r/xml2_html.result | 30 + .../mysql-test/connect/r/xml2_mdev5261.result | 23 + .../connect/mysql-test/connect/r/xml2_mult.result | 102 + .../connect/mysql-test/connect/r/xml2_zip.result | 96 + .../connect/mysql-test/connect/r/xml_grant.result | 105 + .../connect/mysql-test/connect/r/xml_html.result | 30 + .../mysql-test/connect/r/xml_mdev5261.result | 23 + .../connect/mysql-test/connect/r/xml_mult.result | 102 + .../connect/mysql-test/connect/r/xml_zip.result | 96 + storage/connect/mysql-test/connect/r/zip.result | 240 + .../mysql-test/connect/std_data/JavaWrappers.jar | Bin 0 -> 19192 bytes .../mysql-test/connect/std_data/JdbcMariaDB.jar | Bin 0 -> 6021947 bytes .../connect/mysql-test/connect/std_data/Mongo2.jar | Bin 0 -> 624130 bytes .../connect/mysql-test/connect/std_data/Mongo3.jar | Bin 0 -> 1706057 bytes .../mysql-test/connect/std_data/Testbal.dat | Bin 0 -> 78 bytes .../connect/mysql-test/connect/std_data/beers.xml | 16 + .../connect/mysql-test/connect/std_data/bib0.json | 2 + .../mysql-test/connect/std_data/biblio.json | 43 + .../connect/mysql-test/connect/std_data/bios.json | 273 + .../mysql-test/connect/std_data/bookstore.xml | 31 + .../connect/mysql-test/connect/std_data/boys.txt | 6 + .../mysql-test/connect/std_data/boyswin.txt | 6 + .../mysql-test/connect/std_data/cities.json | 29353 +++++++++++++++++++ .../connect/mysql-test/connect/std_data/coffee.htm | 24 + .../mysql-test/connect/std_data/contact.ini | 23 + .../mysql-test/connect/std_data/contacts.xls | Bin 0 -> 9216 bytes .../connect/mysql-test/connect/std_data/cp1251.xml | 2 + .../connect/mysql-test/connect/std_data/dept.dat | 4 + .../connect/mysql-test/connect/std_data/emp.txt | 4545 +++ .../mysql-test/connect/std_data/employee.dat | 27 + .../mysql-test/connect/std_data/expense.json | 158 + .../mysql-test/connect/std_data/expenses.txt | 24 + .../connect/mysql-test/connect/std_data/funny.txt | 3 + .../connect/mysql-test/connect/std_data/funny2.txt | 3 + .../connect/mysql-test/connect/std_data/girls.txt | 5 + .../connect/mysql-test/connect/std_data/gloss.json | 22 + .../connect/mysql-test/connect/std_data/latin1.xml | 2 + .../mysql-test/connect/std_data/mdev9949.frm | Bin 0 -> 35031 bytes .../mysql-test/connect/std_data/mulexp3.json | 52 + .../mysql-test/connect/std_data/mulexp4.json | 52 + .../mysql-test/connect/std_data/mulexp5.json | 52 + .../connect/mysql-test/connect/std_data/nocs.xml | 2 + .../connect/mysql-test/connect/std_data/people.csv | 3 + .../connect/mysql-test/connect/std_data/sexe.csv | 3 + .../connect/mysql-test/connect/std_data/sitmat.csv | 7 + .../mysql-test/connect/std_data/test.sqlite3 | Bin 0 -> 445440 bytes .../mysql-test/connect/std_data/xsample.xml | 35 + .../mysql-test/connect/std_data/xsample2.xml | 47 + storage/connect/mysql-test/connect/suite.opt | 1 + storage/connect/mysql-test/connect/suite.pm | 16 + storage/connect/mysql-test/connect/t/alter.test | 139 + .../connect/mysql-test/connect/t/alter_engine.test | 11 + .../connect/mysql-test/connect/t/alter_xml.test | 29 + .../connect/mysql-test/connect/t/alter_xml2.test | 29 + storage/connect/mysql-test/connect/t/bin.test | 77 + storage/connect/mysql-test/connect/t/bson.test | 317 + .../connect/mysql-test/connect/t/bson_java_2.test | 14 + .../connect/mysql-test/connect/t/bson_java_3.test | 14 + .../connect/mysql-test/connect/t/bson_mongo_c.test | 10 + storage/connect/mysql-test/connect/t/bson_udf.inc | 72 + storage/connect/mysql-test/connect/t/bson_udf.test | 282 + storage/connect/mysql-test/connect/t/bson_udf2.inc | 63 + storage/connect/mysql-test/connect/t/csv.test | 185 + storage/connect/mysql-test/connect/t/datest.test | 28 + storage/connect/mysql-test/connect/t/dbf.test | 511 + storage/connect/mysql-test/connect/t/dir.test | 53 + .../mysql-test/connect/t/drop-open-error.opt | 1 + .../mysql-test/connect/t/drop-open-error.test | 29 + storage/connect/mysql-test/connect/t/endian.test | 88 + storage/connect/mysql-test/connect/t/fix.test | 108 + storage/connect/mysql-test/connect/t/fmt.test | 85 + storage/connect/mysql-test/connect/t/general.test | 33 + storage/connect/mysql-test/connect/t/grant.inc | 86 + storage/connect/mysql-test/connect/t/grant.test | 96 + storage/connect/mysql-test/connect/t/grant2.test | 869 + storage/connect/mysql-test/connect/t/grant3.test | 11 + .../connect/mysql-test/connect/t/have_libxml2.inc | 19 + storage/connect/mysql-test/connect/t/have_odbc.inc | 9 + .../mysql-test/connect/t/have_odbc_oracle.inc | 15 + .../mysql-test/connect/t/have_odbc_postgresql.inc | 15 + .../mysql-test/connect/t/have_odbc_sqlite3.inc | 15 + storage/connect/mysql-test/connect/t/have_zip.inc | 19 + storage/connect/mysql-test/connect/t/index.test | 86 + .../mysql-test/connect/t/infoschema-9739.test | 9 + .../mysql-test/connect/t/infoschema2-9739.test | 9 + storage/connect/mysql-test/connect/t/ini.test | 156 + .../connect/mysql-test/connect/t/ini_grant.test | 81 + storage/connect/mysql-test/connect/t/jdbc.test | 150 + storage/connect/mysql-test/connect/t/jdbc_new.test | 187 + .../connect/mysql-test/connect/t/jdbc_oracle.test | 56 + .../mysql-test/connect/t/jdbc_postgresql.test | 64 + storage/connect/mysql-test/connect/t/jdbconn.inc | 33 + .../mysql-test/connect/t/jdbconn_cleanup.inc | 8 + storage/connect/mysql-test/connect/t/json.test | 318 + .../connect/mysql-test/connect/t/json_java_2.test | 14 + .../connect/mysql-test/connect/t/json_java_3.test | 14 + .../connect/mysql-test/connect/t/json_mongo_c.test | 10 + storage/connect/mysql-test/connect/t/json_udf.inc | 60 + storage/connect/mysql-test/connect/t/json_udf.test | 268 + storage/connect/mysql-test/connect/t/json_udf2.inc | 51 + .../connect/mysql-test/connect/t/json_udf_bin.test | 213 + storage/connect/mysql-test/connect/t/misc.test | 142 + storage/connect/mysql-test/connect/t/mongo.inc | 11 + storage/connect/mysql-test/connect/t/mongo_c.test | 9 + .../connect/mysql-test/connect/t/mongo_java_2.test | 12 + .../connect/mysql-test/connect/t/mongo_java_3.test | 12 + .../connect/mysql-test/connect/t/mongo_test.inc | 216 + storage/connect/mysql-test/connect/t/mrr.test | 66 + storage/connect/mysql-test/connect/t/mul.test | 43 + storage/connect/mysql-test/connect/t/mul_new.test | 67 + storage/connect/mysql-test/connect/t/myconn.inc | 27 + .../mysql-test/connect/t/myconn_cleanup.inc | 9 + storage/connect/mysql-test/connect/t/mysql.test | 508 + .../mysql-test/connect/t/mysql_discovery.test | 33 + .../connect/mysql-test/connect/t/mysql_exec.test | 45 + .../connect/mysql-test/connect/t/mysql_grant.test | 80 + .../connect/mysql-test/connect/t/mysql_index.test | 145 + .../connect/mysql-test/connect/t/mysql_new.test | 325 + storage/connect/mysql-test/connect/t/null.test | 87 + storage/connect/mysql-test/connect/t/occur.test | 61 + storage/connect/mysql-test/connect/t/odbc.test | 25 + .../mysql-test/connect/t/odbc_firebird.test | 35 + .../connect/mysql-test/connect/t/odbc_oracle.sql | 16 + .../connect/mysql-test/connect/t/odbc_oracle.test | 230 + .../mysql-test/connect/t/odbc_postgresql.sql | 32 + .../mysql-test/connect/t/odbc_postgresql.test | 225 + .../connect/mysql-test/connect/t/odbc_sqlite3.test | 90 + .../mysql-test/connect/t/odbc_sqlite3_grant.test | 91 + storage/connect/mysql-test/connect/t/odbc_xls.test | 39 + .../connect/mysql-test/connect/t/part_file.test | 166 + .../connect/mysql-test/connect/t/part_table.test | 107 + storage/connect/mysql-test/connect/t/pivot.test | 163 + storage/connect/mysql-test/connect/t/rest.inc | 17 + storage/connect/mysql-test/connect/t/rest.test | 17 + .../connect/t/secure_file_priv-master.opt | 1 + .../mysql-test/connect/t/secure_file_priv.test | 13 + storage/connect/mysql-test/connect/t/tbl.test | 53 + .../connect/mysql-test/connect/t/tbl_thread.test | 112 + .../connect/mysql-test/connect/t/temporary.test | 13 + .../connect/mysql-test/connect/t/type_inet6.test | 10 + storage/connect/mysql-test/connect/t/unsigned.test | 35 + storage/connect/mysql-test/connect/t/upd.test | 157 + storage/connect/mysql-test/connect/t/updelx.inc | 25 + storage/connect/mysql-test/connect/t/updelx.test | 96 + storage/connect/mysql-test/connect/t/updelx2.test | 22 + storage/connect/mysql-test/connect/t/vcol.test | 31 + storage/connect/mysql-test/connect/t/vec.test | 80 + storage/connect/mysql-test/connect/t/windows.inc | 5 + storage/connect/mysql-test/connect/t/xcol.test | 41 + storage/connect/mysql-test/connect/t/xml.test | 321 + storage/connect/mysql-test/connect/t/xml2.test | 320 + .../connect/mysql-test/connect/t/xml2_grant.test | 8 + .../connect/mysql-test/connect/t/xml2_html.test | 39 + .../mysql-test/connect/t/xml2_mdev5261.test | 27 + .../connect/mysql-test/connect/t/xml2_mult.test | 64 + storage/connect/mysql-test/connect/t/xml2_zip.test | 41 + .../connect/mysql-test/connect/t/xml_grant.test | 8 + storage/connect/mysql-test/connect/t/xml_html.test | 39 + .../connect/mysql-test/connect/t/xml_mdev5261.test | 27 + storage/connect/mysql-test/connect/t/xml_mult.test | 64 + storage/connect/mysql-test/connect/t/xml_zip.test | 41 + storage/connect/mysql-test/connect/t/zip.test | 136 + storage/connect/myutil.cpp | 318 + storage/connect/myutil.h | 14 + storage/connect/noconst.c | 38 + storage/connect/odbccat.h | 25 + storage/connect/odbconn.cpp | 2654 ++ storage/connect/odbconn.h | 202 + storage/connect/os.h | 70 + storage/connect/osutil.c | 179 + storage/connect/osutil.h | 58 + storage/connect/plgcnx.h | 67 + storage/connect/plgdbsem.h | 647 + storage/connect/plgdbutl.cpp | 1614 + storage/connect/plgodbc.h | 230 + storage/connect/plgxml.cpp | 185 + storage/connect/plgxml.h | 194 + storage/connect/plugutil.cpp | 644 + storage/connect/preparse.h | 34 + storage/connect/rcmsg.c | 58 + storage/connect/rcmsg.h | 15 + storage/connect/reldef.cpp | 955 + storage/connect/reldef.h | 251 + storage/connect/resource.h | 46 + storage/connect/rest.def | 4 + storage/connect/restget.cpp | 90 + storage/connect/tabbson.cpp | 2632 ++ storage/connect/tabbson.h | 344 + storage/connect/tabcmg.cpp | 506 + storage/connect/tabcmg.h | 133 + storage/connect/tabcol.cpp | 169 + storage/connect/tabcol.h | 109 + storage/connect/tabdos.cpp | 2921 ++ storage/connect/tabdos.h | 269 + storage/connect/tabext.cpp | 800 + storage/connect/tabext.h | 205 + storage/connect/tabfix.cpp | 681 + storage/connect/tabfix.h | 117 + storage/connect/tabfmt.cpp | 1573 + storage/connect/tabfmt.h | 191 + storage/connect/tabjdbc.cpp | 1328 + storage/connect/tabjdbc.h | 236 + storage/connect/tabjmg.cpp | 632 + storage/connect/tabjmg.h | 147 + storage/connect/tabjson.cpp | 2706 ++ storage/connect/tabjson.h | 323 + storage/connect/table.cpp | 805 + storage/connect/tabmac.cpp | 458 + storage/connect/tabmac.h | 108 + storage/connect/tabmul.cpp | 1623 + storage/connect/tabmul.h | 248 + storage/connect/tabmysql.cpp | 1755 ++ storage/connect/tabmysql.h | 254 + storage/connect/taboccur.cpp | 589 + storage/connect/taboccur.h | 142 + storage/connect/tabodbc.cpp | 1411 + storage/connect/tabodbc.h | 264 + storage/connect/tabpivot.cpp | 912 + storage/connect/tabpivot.h | 200 + storage/connect/tabrest.cpp | 363 + storage/connect/tabrest.h | 48 + storage/connect/tabsys.cpp | 884 + storage/connect/tabsys.h | 182 + storage/connect/tabtbl.cpp | 876 + storage/connect/tabtbl.h | 168 + storage/connect/tabutil.cpp | 804 + storage/connect/tabutil.h | 155 + storage/connect/tabvct.cpp | 588 + storage/connect/tabvct.h | 124 + storage/connect/tabvir.cpp | 305 + storage/connect/tabvir.h | 110 + storage/connect/tabwmi.cpp | 851 + storage/connect/tabwmi.h | 151 + storage/connect/tabxcl.cpp | 298 + storage/connect/tabxcl.h | 104 + storage/connect/tabxml.cpp | 2300 ++ storage/connect/tabxml.h | 273 + storage/connect/tabzip.cpp | 251 + storage/connect/tabzip.h | 102 + storage/connect/unzip.c | 2125 ++ storage/connect/unzip.h | 437 + storage/connect/user_connect.cc | 192 + storage/connect/user_connect.h | 73 + storage/connect/valblk.cpp | 1416 + storage/connect/valblk.h | 375 + storage/connect/value.cpp | 2891 ++ storage/connect/value.h | 451 + storage/connect/xindex.cpp | 3298 +++ storage/connect/xindex.h | 509 + storage/connect/xobject.cpp | 441 + storage/connect/xobject.h | 165 + storage/connect/xtable.h | 275 + storage/connect/zip.c | 2007 ++ storage/connect/zip.h | 362 + 427 files changed, 193311 insertions(+) create mode 100644 storage/connect/.gitignore create mode 100644 storage/connect/ApacheInterface.java create mode 100644 storage/connect/CMakeLists.txt create mode 100644 storage/connect/Client.java create mode 100644 storage/connect/Client2.java create mode 100644 storage/connect/Client3.java create mode 100644 storage/connect/JdbcInterface.java create mode 100644 storage/connect/MariadbInterface.java create mode 100644 storage/connect/Mongo2Interface.java create mode 100644 storage/connect/Mongo3Interface.java create mode 100644 storage/connect/MysqlInterface.java create mode 100644 storage/connect/OracleInterface.java create mode 100644 storage/connect/PostgresqlInterface.java create mode 100644 storage/connect/TestInsert2.java create mode 100644 storage/connect/TestInsert3.java create mode 100644 storage/connect/array.cpp create mode 100644 storage/connect/array.h create mode 100644 storage/connect/blkfil.cpp create mode 100644 storage/connect/blkfil.h create mode 100644 storage/connect/block.h create mode 100644 storage/connect/bson.cpp create mode 100644 storage/connect/bson.h create mode 100644 storage/connect/bsonudf.cpp create mode 100644 storage/connect/bsonudf.h create mode 100644 storage/connect/catalog.h create mode 100644 storage/connect/checklvl.h create mode 100644 storage/connect/cmgfam.cpp create mode 100644 storage/connect/cmgfam.h create mode 100644 storage/connect/cmgoconn.cpp create mode 100644 storage/connect/cmgoconn.h create mode 100644 storage/connect/colblk.cpp create mode 100644 storage/connect/colblk.h create mode 100644 storage/connect/connect.cc create mode 100644 storage/connect/connect.h create mode 100644 storage/connect/csort.cpp create mode 100644 storage/connect/csort.h create mode 100644 storage/connect/domdoc.cpp create mode 100644 storage/connect/domdoc.h create mode 100644 storage/connect/encas.h create mode 100644 storage/connect/engmsg.h create mode 100644 storage/connect/enids.h create mode 100644 storage/connect/filamap.cpp create mode 100644 storage/connect/filamap.h create mode 100644 storage/connect/filamdbf.cpp create mode 100644 storage/connect/filamdbf.h create mode 100644 storage/connect/filamfix.cpp create mode 100644 storage/connect/filamfix.h create mode 100644 storage/connect/filamgz.cpp create mode 100644 storage/connect/filamgz.h create mode 100644 storage/connect/filamtxt.cpp create mode 100644 storage/connect/filamtxt.h create mode 100644 storage/connect/filamvct.cpp create mode 100644 storage/connect/filamvct.h create mode 100644 storage/connect/filamzip.cpp create mode 100644 storage/connect/filamzip.h create mode 100644 storage/connect/filter.cpp create mode 100644 storage/connect/filter.h create mode 100644 storage/connect/fmdlex.c create mode 100644 storage/connect/global.h create mode 100644 storage/connect/ha_connect.cc create mode 100644 storage/connect/ha_connect.h create mode 100644 storage/connect/inihandl.cpp create mode 100644 storage/connect/inihandl.h create mode 100644 storage/connect/ioapi.c create mode 100644 storage/connect/ioapi.h create mode 100644 storage/connect/javaconn.cpp create mode 100644 storage/connect/javaconn.h create mode 100644 storage/connect/jdbccat.h create mode 100644 storage/connect/jdbconn.cpp create mode 100644 storage/connect/jdbconn.h create mode 100644 storage/connect/jmgfam.cpp create mode 100644 storage/connect/jmgfam.h create mode 100644 storage/connect/jmgoconn.cpp create mode 100644 storage/connect/jmgoconn.h create mode 100644 storage/connect/json.cpp create mode 100644 storage/connect/json.h create mode 100644 storage/connect/jsonudf.cpp create mode 100644 storage/connect/jsonudf.h create mode 100644 storage/connect/libdoc.cpp create mode 100644 storage/connect/libdoc.h create mode 100644 storage/connect/macutil.cpp create mode 100644 storage/connect/macutil.h create mode 100644 storage/connect/maputil.cpp create mode 100644 storage/connect/maputil.h create mode 100644 storage/connect/messages.h create mode 100644 storage/connect/mini-global.h create mode 100644 storage/connect/mongo.cpp create mode 100644 storage/connect/mongo.h create mode 100644 storage/connect/msgid.h create mode 100644 storage/connect/mycat.cc create mode 100644 storage/connect/mycat.h create mode 100644 storage/connect/myconn.cpp create mode 100644 storage/connect/myconn.h create mode 100644 storage/connect/mysql-test/connect/disabled.def create mode 100644 storage/connect/mysql-test/connect/my.cnf create mode 100644 storage/connect/mysql-test/connect/r/alter.result create mode 100644 storage/connect/mysql-test/connect/r/alter_engine.result create mode 100644 storage/connect/mysql-test/connect/r/alter_xml.result create mode 100644 storage/connect/mysql-test/connect/r/alter_xml2.result create mode 100644 storage/connect/mysql-test/connect/r/bin.result create mode 100644 storage/connect/mysql-test/connect/r/bson.result create mode 100644 storage/connect/mysql-test/connect/r/bson_java_2.result create mode 100644 storage/connect/mysql-test/connect/r/bson_java_3.result create mode 100644 storage/connect/mysql-test/connect/r/bson_mongo_c.result create mode 100644 storage/connect/mysql-test/connect/r/bson_udf.result create mode 100644 storage/connect/mysql-test/connect/r/csv.result create mode 100644 storage/connect/mysql-test/connect/r/datest.result create mode 100644 storage/connect/mysql-test/connect/r/dbf.result create mode 100644 storage/connect/mysql-test/connect/r/dir.result create mode 100644 storage/connect/mysql-test/connect/r/drop-open-error.result create mode 100644 storage/connect/mysql-test/connect/r/endian.result create mode 100644 storage/connect/mysql-test/connect/r/fix.result create mode 100644 storage/connect/mysql-test/connect/r/fmt.result create mode 100644 storage/connect/mysql-test/connect/r/general.result create mode 100644 storage/connect/mysql-test/connect/r/grant.result create mode 100644 storage/connect/mysql-test/connect/r/grant2.result create mode 100644 storage/connect/mysql-test/connect/r/grant3.result create mode 100644 storage/connect/mysql-test/connect/r/index.result create mode 100644 storage/connect/mysql-test/connect/r/infoschema-9739.result create mode 100644 storage/connect/mysql-test/connect/r/infoschema2-9739.result create mode 100644 storage/connect/mysql-test/connect/r/ini.result create mode 100644 storage/connect/mysql-test/connect/r/ini_grant.result create mode 100644 storage/connect/mysql-test/connect/r/jdbc.result create mode 100644 storage/connect/mysql-test/connect/r/jdbc_new.result create mode 100644 storage/connect/mysql-test/connect/r/jdbc_oracle.result create mode 100644 storage/connect/mysql-test/connect/r/jdbc_postgresql.result create mode 100644 storage/connect/mysql-test/connect/r/json.result create mode 100644 storage/connect/mysql-test/connect/r/json_java_2.result create mode 100644 storage/connect/mysql-test/connect/r/json_java_3.result create mode 100644 storage/connect/mysql-test/connect/r/json_mongo_c.result create mode 100644 storage/connect/mysql-test/connect/r/json_udf.result create mode 100644 storage/connect/mysql-test/connect/r/json_udf_bin.result create mode 100644 storage/connect/mysql-test/connect/r/misc.result create mode 100644 storage/connect/mysql-test/connect/r/mongo_c.result create mode 100644 storage/connect/mysql-test/connect/r/mongo_java_2.result create mode 100644 storage/connect/mysql-test/connect/r/mongo_java_3.result create mode 100644 storage/connect/mysql-test/connect/r/mrr.result create mode 100644 storage/connect/mysql-test/connect/r/mul.result create mode 100644 storage/connect/mysql-test/connect/r/mul_new.result create mode 100644 storage/connect/mysql-test/connect/r/mysql.result create mode 100644 storage/connect/mysql-test/connect/r/mysql_discovery.result create mode 100644 storage/connect/mysql-test/connect/r/mysql_exec.result create mode 100644 storage/connect/mysql-test/connect/r/mysql_grant.result create mode 100644 storage/connect/mysql-test/connect/r/mysql_index.result create mode 100644 storage/connect/mysql-test/connect/r/mysql_new.result create mode 100644 storage/connect/mysql-test/connect/r/null.result create mode 100644 storage/connect/mysql-test/connect/r/occur.result create mode 100644 storage/connect/mysql-test/connect/r/odbc.result create mode 100644 storage/connect/mysql-test/connect/r/odbc_firebird.result create mode 100644 storage/connect/mysql-test/connect/r/odbc_oracle.result create mode 100644 storage/connect/mysql-test/connect/r/odbc_postgresql.result create mode 100644 storage/connect/mysql-test/connect/r/odbc_sqlite3.result create mode 100644 storage/connect/mysql-test/connect/r/odbc_sqlite3_grant.result create mode 100644 storage/connect/mysql-test/connect/r/odbc_xls.result create mode 100644 storage/connect/mysql-test/connect/r/part_file.result create mode 100644 storage/connect/mysql-test/connect/r/part_table.result create mode 100644 storage/connect/mysql-test/connect/r/pivot.result create mode 100644 storage/connect/mysql-test/connect/r/rest.result create mode 100644 storage/connect/mysql-test/connect/r/secure_file_priv.result create mode 100644 storage/connect/mysql-test/connect/r/tbl.result create mode 100644 storage/connect/mysql-test/connect/r/tbl_thread.result create mode 100644 storage/connect/mysql-test/connect/r/temporary.result create mode 100644 storage/connect/mysql-test/connect/r/type_inet6.result create mode 100644 storage/connect/mysql-test/connect/r/unsigned.result create mode 100644 storage/connect/mysql-test/connect/r/upd.result create mode 100644 storage/connect/mysql-test/connect/r/updelx.result create mode 100644 storage/connect/mysql-test/connect/r/updelx2.result create mode 100644 storage/connect/mysql-test/connect/r/vcol.result create mode 100644 storage/connect/mysql-test/connect/r/vec.result create mode 100644 storage/connect/mysql-test/connect/r/xcol.result create mode 100644 storage/connect/mysql-test/connect/r/xml.result create mode 100644 storage/connect/mysql-test/connect/r/xml2.result create mode 100644 storage/connect/mysql-test/connect/r/xml2_grant.result create mode 100644 storage/connect/mysql-test/connect/r/xml2_html.result create mode 100644 storage/connect/mysql-test/connect/r/xml2_mdev5261.result create mode 100644 storage/connect/mysql-test/connect/r/xml2_mult.result create mode 100644 storage/connect/mysql-test/connect/r/xml2_zip.result create mode 100644 storage/connect/mysql-test/connect/r/xml_grant.result create mode 100644 storage/connect/mysql-test/connect/r/xml_html.result create mode 100644 storage/connect/mysql-test/connect/r/xml_mdev5261.result create mode 100644 storage/connect/mysql-test/connect/r/xml_mult.result create mode 100644 storage/connect/mysql-test/connect/r/xml_zip.result create mode 100644 storage/connect/mysql-test/connect/r/zip.result create mode 100644 storage/connect/mysql-test/connect/std_data/JavaWrappers.jar create mode 100644 storage/connect/mysql-test/connect/std_data/JdbcMariaDB.jar create mode 100644 storage/connect/mysql-test/connect/std_data/Mongo2.jar create mode 100644 storage/connect/mysql-test/connect/std_data/Mongo3.jar create mode 100644 storage/connect/mysql-test/connect/std_data/Testbal.dat create mode 100644 storage/connect/mysql-test/connect/std_data/beers.xml create mode 100644 storage/connect/mysql-test/connect/std_data/bib0.json create mode 100644 storage/connect/mysql-test/connect/std_data/biblio.json create mode 100644 storage/connect/mysql-test/connect/std_data/bios.json create mode 100644 storage/connect/mysql-test/connect/std_data/bookstore.xml create mode 100644 storage/connect/mysql-test/connect/std_data/boys.txt create mode 100644 storage/connect/mysql-test/connect/std_data/boyswin.txt create mode 100644 storage/connect/mysql-test/connect/std_data/cities.json create mode 100644 storage/connect/mysql-test/connect/std_data/coffee.htm create mode 100644 storage/connect/mysql-test/connect/std_data/contact.ini create mode 100644 storage/connect/mysql-test/connect/std_data/contacts.xls create mode 100644 storage/connect/mysql-test/connect/std_data/cp1251.xml create mode 100644 storage/connect/mysql-test/connect/std_data/dept.dat create mode 100644 storage/connect/mysql-test/connect/std_data/emp.txt create mode 100644 storage/connect/mysql-test/connect/std_data/employee.dat create mode 100644 storage/connect/mysql-test/connect/std_data/expense.json create mode 100644 storage/connect/mysql-test/connect/std_data/expenses.txt create mode 100644 storage/connect/mysql-test/connect/std_data/funny.txt create mode 100644 storage/connect/mysql-test/connect/std_data/funny2.txt create mode 100644 storage/connect/mysql-test/connect/std_data/girls.txt create mode 100644 storage/connect/mysql-test/connect/std_data/gloss.json create mode 100644 storage/connect/mysql-test/connect/std_data/latin1.xml create mode 100644 storage/connect/mysql-test/connect/std_data/mdev9949.frm create mode 100644 storage/connect/mysql-test/connect/std_data/mulexp3.json create mode 100644 storage/connect/mysql-test/connect/std_data/mulexp4.json create mode 100644 storage/connect/mysql-test/connect/std_data/mulexp5.json create mode 100644 storage/connect/mysql-test/connect/std_data/nocs.xml create mode 100644 storage/connect/mysql-test/connect/std_data/people.csv create mode 100644 storage/connect/mysql-test/connect/std_data/sexe.csv create mode 100644 storage/connect/mysql-test/connect/std_data/sitmat.csv create mode 100644 storage/connect/mysql-test/connect/std_data/test.sqlite3 create mode 100644 storage/connect/mysql-test/connect/std_data/xsample.xml create mode 100644 storage/connect/mysql-test/connect/std_data/xsample2.xml create mode 100644 storage/connect/mysql-test/connect/suite.opt create mode 100644 storage/connect/mysql-test/connect/suite.pm create mode 100644 storage/connect/mysql-test/connect/t/alter.test create mode 100644 storage/connect/mysql-test/connect/t/alter_engine.test create mode 100644 storage/connect/mysql-test/connect/t/alter_xml.test create mode 100644 storage/connect/mysql-test/connect/t/alter_xml2.test create mode 100644 storage/connect/mysql-test/connect/t/bin.test create mode 100644 storage/connect/mysql-test/connect/t/bson.test create mode 100644 storage/connect/mysql-test/connect/t/bson_java_2.test create mode 100644 storage/connect/mysql-test/connect/t/bson_java_3.test create mode 100644 storage/connect/mysql-test/connect/t/bson_mongo_c.test create mode 100644 storage/connect/mysql-test/connect/t/bson_udf.inc create mode 100644 storage/connect/mysql-test/connect/t/bson_udf.test create mode 100644 storage/connect/mysql-test/connect/t/bson_udf2.inc create mode 100644 storage/connect/mysql-test/connect/t/csv.test create mode 100644 storage/connect/mysql-test/connect/t/datest.test create mode 100644 storage/connect/mysql-test/connect/t/dbf.test create mode 100644 storage/connect/mysql-test/connect/t/dir.test create mode 100644 storage/connect/mysql-test/connect/t/drop-open-error.opt create mode 100644 storage/connect/mysql-test/connect/t/drop-open-error.test create mode 100644 storage/connect/mysql-test/connect/t/endian.test create mode 100644 storage/connect/mysql-test/connect/t/fix.test create mode 100644 storage/connect/mysql-test/connect/t/fmt.test create mode 100644 storage/connect/mysql-test/connect/t/general.test create mode 100644 storage/connect/mysql-test/connect/t/grant.inc create mode 100644 storage/connect/mysql-test/connect/t/grant.test create mode 100644 storage/connect/mysql-test/connect/t/grant2.test create mode 100644 storage/connect/mysql-test/connect/t/grant3.test create mode 100644 storage/connect/mysql-test/connect/t/have_libxml2.inc create mode 100644 storage/connect/mysql-test/connect/t/have_odbc.inc create mode 100644 storage/connect/mysql-test/connect/t/have_odbc_oracle.inc create mode 100644 storage/connect/mysql-test/connect/t/have_odbc_postgresql.inc create mode 100644 storage/connect/mysql-test/connect/t/have_odbc_sqlite3.inc create mode 100644 storage/connect/mysql-test/connect/t/have_zip.inc create mode 100644 storage/connect/mysql-test/connect/t/index.test create mode 100644 storage/connect/mysql-test/connect/t/infoschema-9739.test create mode 100644 storage/connect/mysql-test/connect/t/infoschema2-9739.test create mode 100644 storage/connect/mysql-test/connect/t/ini.test create mode 100644 storage/connect/mysql-test/connect/t/ini_grant.test create mode 100644 storage/connect/mysql-test/connect/t/jdbc.test create mode 100644 storage/connect/mysql-test/connect/t/jdbc_new.test create mode 100644 storage/connect/mysql-test/connect/t/jdbc_oracle.test create mode 100644 storage/connect/mysql-test/connect/t/jdbc_postgresql.test create mode 100644 storage/connect/mysql-test/connect/t/jdbconn.inc create mode 100644 storage/connect/mysql-test/connect/t/jdbconn_cleanup.inc create mode 100644 storage/connect/mysql-test/connect/t/json.test create mode 100644 storage/connect/mysql-test/connect/t/json_java_2.test create mode 100644 storage/connect/mysql-test/connect/t/json_java_3.test create mode 100644 storage/connect/mysql-test/connect/t/json_mongo_c.test create mode 100644 storage/connect/mysql-test/connect/t/json_udf.inc create mode 100644 storage/connect/mysql-test/connect/t/json_udf.test create mode 100644 storage/connect/mysql-test/connect/t/json_udf2.inc create mode 100644 storage/connect/mysql-test/connect/t/json_udf_bin.test create mode 100644 storage/connect/mysql-test/connect/t/misc.test create mode 100644 storage/connect/mysql-test/connect/t/mongo.inc create mode 100644 storage/connect/mysql-test/connect/t/mongo_c.test create mode 100644 storage/connect/mysql-test/connect/t/mongo_java_2.test create mode 100644 storage/connect/mysql-test/connect/t/mongo_java_3.test create mode 100644 storage/connect/mysql-test/connect/t/mongo_test.inc create mode 100644 storage/connect/mysql-test/connect/t/mrr.test create mode 100644 storage/connect/mysql-test/connect/t/mul.test create mode 100644 storage/connect/mysql-test/connect/t/mul_new.test create mode 100644 storage/connect/mysql-test/connect/t/myconn.inc create mode 100644 storage/connect/mysql-test/connect/t/myconn_cleanup.inc create mode 100644 storage/connect/mysql-test/connect/t/mysql.test create mode 100644 storage/connect/mysql-test/connect/t/mysql_discovery.test create mode 100644 storage/connect/mysql-test/connect/t/mysql_exec.test create mode 100644 storage/connect/mysql-test/connect/t/mysql_grant.test create mode 100644 storage/connect/mysql-test/connect/t/mysql_index.test create mode 100644 storage/connect/mysql-test/connect/t/mysql_new.test create mode 100644 storage/connect/mysql-test/connect/t/null.test create mode 100644 storage/connect/mysql-test/connect/t/occur.test create mode 100644 storage/connect/mysql-test/connect/t/odbc.test create mode 100644 storage/connect/mysql-test/connect/t/odbc_firebird.test create mode 100644 storage/connect/mysql-test/connect/t/odbc_oracle.sql create mode 100644 storage/connect/mysql-test/connect/t/odbc_oracle.test create mode 100644 storage/connect/mysql-test/connect/t/odbc_postgresql.sql create mode 100644 storage/connect/mysql-test/connect/t/odbc_postgresql.test create mode 100644 storage/connect/mysql-test/connect/t/odbc_sqlite3.test create mode 100644 storage/connect/mysql-test/connect/t/odbc_sqlite3_grant.test create mode 100644 storage/connect/mysql-test/connect/t/odbc_xls.test create mode 100644 storage/connect/mysql-test/connect/t/part_file.test create mode 100644 storage/connect/mysql-test/connect/t/part_table.test create mode 100644 storage/connect/mysql-test/connect/t/pivot.test create mode 100644 storage/connect/mysql-test/connect/t/rest.inc create mode 100644 storage/connect/mysql-test/connect/t/rest.test create mode 100644 storage/connect/mysql-test/connect/t/secure_file_priv-master.opt create mode 100644 storage/connect/mysql-test/connect/t/secure_file_priv.test create mode 100644 storage/connect/mysql-test/connect/t/tbl.test create mode 100644 storage/connect/mysql-test/connect/t/tbl_thread.test create mode 100644 storage/connect/mysql-test/connect/t/temporary.test create mode 100644 storage/connect/mysql-test/connect/t/type_inet6.test create mode 100644 storage/connect/mysql-test/connect/t/unsigned.test create mode 100644 storage/connect/mysql-test/connect/t/upd.test create mode 100644 storage/connect/mysql-test/connect/t/updelx.inc create mode 100644 storage/connect/mysql-test/connect/t/updelx.test create mode 100644 storage/connect/mysql-test/connect/t/updelx2.test create mode 100644 storage/connect/mysql-test/connect/t/vcol.test create mode 100644 storage/connect/mysql-test/connect/t/vec.test create mode 100644 storage/connect/mysql-test/connect/t/windows.inc create mode 100644 storage/connect/mysql-test/connect/t/xcol.test create mode 100644 storage/connect/mysql-test/connect/t/xml.test create mode 100644 storage/connect/mysql-test/connect/t/xml2.test create mode 100644 storage/connect/mysql-test/connect/t/xml2_grant.test create mode 100644 storage/connect/mysql-test/connect/t/xml2_html.test create mode 100644 storage/connect/mysql-test/connect/t/xml2_mdev5261.test create mode 100644 storage/connect/mysql-test/connect/t/xml2_mult.test create mode 100644 storage/connect/mysql-test/connect/t/xml2_zip.test create mode 100644 storage/connect/mysql-test/connect/t/xml_grant.test create mode 100644 storage/connect/mysql-test/connect/t/xml_html.test create mode 100644 storage/connect/mysql-test/connect/t/xml_mdev5261.test create mode 100644 storage/connect/mysql-test/connect/t/xml_mult.test create mode 100644 storage/connect/mysql-test/connect/t/xml_zip.test create mode 100644 storage/connect/mysql-test/connect/t/zip.test create mode 100644 storage/connect/myutil.cpp create mode 100644 storage/connect/myutil.h create mode 100644 storage/connect/noconst.c create mode 100644 storage/connect/odbccat.h create mode 100644 storage/connect/odbconn.cpp create mode 100644 storage/connect/odbconn.h create mode 100644 storage/connect/os.h create mode 100644 storage/connect/osutil.c create mode 100644 storage/connect/osutil.h create mode 100644 storage/connect/plgcnx.h create mode 100644 storage/connect/plgdbsem.h create mode 100644 storage/connect/plgdbutl.cpp create mode 100644 storage/connect/plgodbc.h create mode 100644 storage/connect/plgxml.cpp create mode 100644 storage/connect/plgxml.h create mode 100644 storage/connect/plugutil.cpp create mode 100644 storage/connect/preparse.h create mode 100644 storage/connect/rcmsg.c create mode 100644 storage/connect/rcmsg.h create mode 100644 storage/connect/reldef.cpp create mode 100644 storage/connect/reldef.h create mode 100644 storage/connect/resource.h create mode 100644 storage/connect/rest.def create mode 100644 storage/connect/restget.cpp create mode 100644 storage/connect/tabbson.cpp create mode 100644 storage/connect/tabbson.h create mode 100644 storage/connect/tabcmg.cpp create mode 100644 storage/connect/tabcmg.h create mode 100644 storage/connect/tabcol.cpp create mode 100644 storage/connect/tabcol.h create mode 100644 storage/connect/tabdos.cpp create mode 100644 storage/connect/tabdos.h create mode 100644 storage/connect/tabext.cpp create mode 100644 storage/connect/tabext.h create mode 100644 storage/connect/tabfix.cpp create mode 100644 storage/connect/tabfix.h create mode 100644 storage/connect/tabfmt.cpp create mode 100644 storage/connect/tabfmt.h create mode 100644 storage/connect/tabjdbc.cpp create mode 100644 storage/connect/tabjdbc.h create mode 100644 storage/connect/tabjmg.cpp create mode 100644 storage/connect/tabjmg.h create mode 100644 storage/connect/tabjson.cpp create mode 100644 storage/connect/tabjson.h create mode 100644 storage/connect/table.cpp create mode 100644 storage/connect/tabmac.cpp create mode 100644 storage/connect/tabmac.h create mode 100644 storage/connect/tabmul.cpp create mode 100644 storage/connect/tabmul.h create mode 100644 storage/connect/tabmysql.cpp create mode 100644 storage/connect/tabmysql.h create mode 100644 storage/connect/taboccur.cpp create mode 100644 storage/connect/taboccur.h create mode 100644 storage/connect/tabodbc.cpp create mode 100644 storage/connect/tabodbc.h create mode 100644 storage/connect/tabpivot.cpp create mode 100644 storage/connect/tabpivot.h create mode 100644 storage/connect/tabrest.cpp create mode 100644 storage/connect/tabrest.h create mode 100644 storage/connect/tabsys.cpp create mode 100644 storage/connect/tabsys.h create mode 100644 storage/connect/tabtbl.cpp create mode 100644 storage/connect/tabtbl.h create mode 100644 storage/connect/tabutil.cpp create mode 100644 storage/connect/tabutil.h create mode 100644 storage/connect/tabvct.cpp create mode 100644 storage/connect/tabvct.h create mode 100644 storage/connect/tabvir.cpp create mode 100644 storage/connect/tabvir.h create mode 100644 storage/connect/tabwmi.cpp create mode 100644 storage/connect/tabwmi.h create mode 100644 storage/connect/tabxcl.cpp create mode 100644 storage/connect/tabxcl.h create mode 100644 storage/connect/tabxml.cpp create mode 100644 storage/connect/tabxml.h create mode 100644 storage/connect/tabzip.cpp create mode 100644 storage/connect/tabzip.h create mode 100644 storage/connect/unzip.c create mode 100644 storage/connect/unzip.h create mode 100644 storage/connect/user_connect.cc create mode 100644 storage/connect/user_connect.h create mode 100644 storage/connect/valblk.cpp create mode 100644 storage/connect/valblk.h create mode 100644 storage/connect/value.cpp create mode 100644 storage/connect/value.h create mode 100644 storage/connect/xindex.cpp create mode 100644 storage/connect/xindex.h create mode 100644 storage/connect/xobject.cpp create mode 100644 storage/connect/xobject.h create mode 100644 storage/connect/xtable.h create mode 100644 storage/connect/zip.c create mode 100644 storage/connect/zip.h (limited to 'storage/connect') 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 pool = new Hashtable(); + + 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..4816086f --- /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(CPACK_RPM_connect-engine_PACKAGE_SUMMARY "Connect storage engine for MariaDB" PARENT_SCOPE) +SET(CPACK_RPM_connect-engine_PACKAGE_DESCRIPTION "Connect engine supports a number of file formats (dbf, xml, txt, bin, etc), +connections to ODBC tables and remote MySQL tables, as well as a number of +other interesting features." PARENT_SCOPE) + +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") + DISABLE_WARNING("deprecated-declarations") + 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() + 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() + + +# +# 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 ). + + 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 +#include +#include +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(MSVC) + IF (libmongoc-1.0_FOUND) + SET_TARGET_PROPERTIES(connect PROPERTIES LINK_FLAGS + "/DELAYLOAD:libbson-1.0.dll /DELAYLOAD:libmongoc-1.0.dll") + ENDIF() + # Temporarily disable "conversion from size_t .." warnings + IF(CMAKE_SIZEOF_VOID_P EQUAL 8) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4267") + ENDIF() + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4996") + string(REPLACE "/permissive-" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + INSTALL(FILES "$/ha_connect.lib" + DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine) +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 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 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 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 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(); + + } // 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 Colnames = null; + Cursor cursor = null; + MongoClient client = null; + DB db = null; + DBCollection coll = null; + BasicDBObject doc = null; + BasicDBObject dbq = null; + BasicDBObject dbf = null; + List 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) 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 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 Colnames = null; + MongoClient client = null; + MongoDatabase db = null; + MongoCollection coll = null; + FindIterable finditer = null; + AggregateIterable aggiter = null; + MongoCursor 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) 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 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(); + + } // 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(); + + } // 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(); + + } // 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..a5c2e065 --- /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 +#else // !_WIN32 +#include +#include +#include +#include // 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) { + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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()) { + snprintf(g->Message, sizeof(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()) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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..692ef98a --- /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 +#else // !_WIN32 +#include +#include +#include +#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) { + snprintf(g->Message, sizeof(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..1eef3c06 --- /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 + +/***********************************************************************/ +/* 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 + +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 + + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(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"))) { + snprintf(g->Message, sizeof(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 +#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..618c0168 --- /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 +#include +#include +#include +#include +#include + +#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 + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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: + DBUG_ASSERT(!"Implement new op type support."); + } // 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: + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(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; + snprintf(s, sizeof(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) { + snprintf(s, sizeof(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)) + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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 = NULL, top = NULL; + PBVAL jsp[2] = {NULL, NULL}; + + for (int i = 0; i < 2; i++) { + jvp = bnx.MakeValue(args, i, true); + + if (i) { + if (jvp && (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)) { + snprintf(g->Message, sizeof(g->Message), "Error %d reading %zu 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) { + snprintf(g->Message, sizeof(g->Message), "Error %d writing %zu bytes to %s", + errno, sizeof(binszp), ofn); + str = strcpy(result, g->Message); + } else if (fwrite(jsp, binszp, 1, fout) != 1) { + snprintf(g->Message, sizeof(g->Message), "Error %d writing %zu 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 jarp = NULL, top = 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)) { + 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 = NULL, top = NULL; + PBVAL jsp[2] = {NULL, NULL}; + + for (int i = 0; i < 2; i++) { + if (i) { + jvp = bnx.MakeValue(args, i, true); + + if (jvp && (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..3ecdb02a --- /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 + +/***********************************************************************/ +/* 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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), "bson_new_from_json: %s", Error.message); + rc = RC_FX; + } else if (!mongoc_collection_insert(Collection, + MONGOC_INSERT_NONE, doc, NULL, &Error)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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()) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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 +#include +#include + +// 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..79fc2a5e --- /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) + { + snprintf(g->Message, sizeof(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) +{ + snprintf(g->Message, sizeof(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) +{ + snprintf(g->Message, sizeof(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) +{ + snprintf(g->Message, sizeof(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..c9712f51 --- /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-2019 */ +/* */ +/* 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..41bce530 --- /dev/null +++ b/storage/connect/connect.cc @@ -0,0 +1,973 @@ +/* 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 +#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. */ + /*********************************************************************/ + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(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))) { + /* If table type is of type virtual retrieve global parameter as it was.*/ + if (tdbp->GetAmType() == TYPE_AM_VIR) { + if (tdbp->OpenDB(g)) { + printf("%s\n", g->Message); + throw 7; + } + } + snprintf(g->Message, sizeof(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->GetAmType() == TYPE_AM_JSN) + 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()) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) + snprintf(g->Message, sizeof(g->Message), "Out of range value for column %s at row %d", + colp->GetName(), tdbp->RowNumber(g)); + else + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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()) { + snprintf(g->Message, sizeof(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)) + snprintf(g->Message, sizeof(g->Message), + "Out of range value for column %s at row %d", + colp->GetName(), tdbp->RowNumber(g)); + else + snprintf(g->Message, sizeof(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..af1b9ba7 --- /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 /* C standard library */ +#include /* String manipulation declares */ +#include /* Required for sprintf declare */ +#if defined(_DEBUG) +#include /* 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 /* 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..268ad771 --- /dev/null +++ b/storage/connect/domdoc.cpp @@ -0,0 +1,755 @@ +/******************************************************************/ +/* Implementation of XML document processing using MS DOM */ +/* Author: Olivier Bertrand 2007 - 2013 */ +/******************************************************************/ +#include "my_global.h" +#include +#if defined(_WIN32) +//#include +#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) { + snprintf(g->Message, sizeof(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()); + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(g->Message), "Truncated %s content", GetName(g)); + rc = RC_INFO; + break; + case ERROR_NO_UNICODE_TRANSLATION: // 1113L + snprintf(g->Message, sizeof(g->Message), "Invalid character(s) in %s content", + GetName(g)); + rc = RC_INFO; + break; + default: + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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; + + 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 + snprintf(g->Message, sizeof(g->Message), "Truncated %s content", GetName(g)); + rc = RC_INFO; + break; + case ERROR_NO_UNICODE_TRANSLATION: // 1113L + snprintf(g->Message, sizeof(g->Message), "Invalid character(s) in %s content", + GetName(g)); + rc = RC_INFO; + break; + default: + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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..1b38ab2e --- /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 +#else // !_WIN32 +#if defined(UNIX) +#include +#include +#else // !UNIX +#include +#endif // !UNIX +#include +#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)) + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(g->Message), MSG(FUNCTION_ERROR), + "SetEndOfFile", GetLastError()); + CloseHandle(fp->Handle); + return RC_FX; + } // endif + +#else // UNIX + if (ftruncate(fp->Handle, (off_t)n)) { + snprintf(g->Message, sizeof(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..c7206b4d --- /dev/null +++ b/storage/connect/filamdbf.cpp @@ -0,0 +1,1203 @@ +/*********** 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 +#include +//#include +//#include +#else // !_WIN32 +#if defined(UNIX) +#include +#include +#else // !UNIX +//#include +#endif // !UNIX +//#include +#endif // !_WIN32 +#include +#include +#include + +/***********************************************************************/ +/* 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" +#include "m_string.h" // For strmake + +/****************************************************************************/ +/* 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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 = NULL; + 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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(g->Message), MSG(BAD_DBF_TYPE), + c, cdp->GetName()); + return true; + } // endswitch c + + strmake(descp->Name, cdp->GetName(), sizeof(descp->Name)-1); + 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) { + snprintf(g->Message, sizeof(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()) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(g->Message), MSG(BAD_READ_NUMBER), (int) n, To_File); + else if ((n = fwrite(hdr, 1, hlen, T_Stream)) != hlen) + snprintf(g->Message, sizeof(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)) + snprintf(g->Message, sizeof(g->Message), MSG(FSETPOS_ERROR), 0); + else if (fread(To_Buf, 1, lrecl, Stream) != lrecl) + snprintf(g->Message, sizeof(g->Message), MSG(READ_ERROR), To_File, strerror(errno)); + else + *To_Buf = '*'; + + if (fseek(Stream, Headlen + fpos * Lrecl, SEEK_SET)) + snprintf(g->Message, sizeof(g->Message), MSG(FSETPOS_ERROR), 0); + else if (fwrite(To_Buf, 1, lrecl, Stream) != lrecl) + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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()) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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..117a4e8d --- /dev/null +++ b/storage/connect/filamfix.cpp @@ -0,0 +1,1539 @@ +/*********** 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 +#include +#include +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif // __BORLANDC__ +//#include +#else // !_WIN32 +#if defined(UNIX) +#include +#include +#else // !UNIX +#include +#endif // !UNIX +#include +#include +#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)) { + snprintf(g->Message, sizeof(g->Message), MSG(FSETPOS_ERROR), 0); + rc = RC_FX; + } else if (fwrite(To_Buf, Lrecl, Rbuf, T_Stream) != (size_t)Rbuf) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(g->Message), MSG(READ_ERROR), To_File, _strerror(NULL)); +#else + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(g->Message), MSG(TRUNCATE_ERROR), strerror(errno)); + close(h); + return RC_FX; + } // endif +#else + if (chsize(h, Tpos * Lrecl)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(g->Message), MSG(WRITE_SEEK_ERR), strerror(errno)); + return true; + } // endif + + if ((len = fwrite(DelBuf, Lrecl, req, T_Stream)) != req) { + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(g->Message), MSG(SFP_ERROR), buf); + return true; + } // endif +#else // !_WIN32 + if (lseek64(h, pos, org) < 0) { + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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 + + snprintf(g->Message, sizeof(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"; + + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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(); + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), MSG(NOT_FIXED_LEN), + filename, (int)fsize, Lrecl); + return -3; + } else + card = (int)(fsize / (BIGINT)Blksize) * Nrec; + + } else if (fsize % (BIGINT)Lrecl) { + snprintf(g->Message, sizeof(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(); + + snprintf(g->Message, sizeof(g->Message), MSG(SETEOF_ERROR), drc); + return RC_FX; + } // endif error +#else // !_WIN32 + if (ftruncate64(Hfile, (BIGINT)(Tpos * Lrecl))) { + snprintf(g->Message, sizeof(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(); + snprintf(g->Message, sizeof(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; + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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..d6c48cb2 --- /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 +#include +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif +//#include +#else // !_WIN32 +#if defined(UNIX) +#include +#else // !UNIX +#include +#endif +#include +#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) + snprintf(g->Message, sizeof(g->Message), MSG(READ_ERROR), To_File, strerror(NULL)); +#else // !_WIN32 + snprintf(g->Message, sizeof(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 { + snprintf(g->Message, sizeof(g->Message), MSG(NO_PART_DEL), "GZ"); + return true; + } // endif filter + + break; + case MODE_INSERT: + strcpy(opmode, "a+"); + break; + default: + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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))) + { + snprintf(g->Message, sizeof(g->Message), MSG(NO_SETPOS_YET), "GZ"); + return true; +#if 0 + Fpos = pos; + + if (fseek(Stream, Fpos, SEEK_SET)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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()) { + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(g->Message), "%s error: %s", msg, Zstream->msg); + else + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(g->Message), MSG(READ_ERROR), To_File, strerror(errno)); +#else + snprintf(g->Message, sizeof(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")) { + snprintf(g->Message, sizeof(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))) + { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(g->Message), MSG(READ_ERROR), To_File, strerror(errno)); +#else + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(g->Message), MSG(FUNC_ERR_S), "inflate", Zstream->msg); + else + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(g->Message), MSG(FUNC_ERR_S), "deflate", Zstream->msg); + else + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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..7a5d16ac --- /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 +#include +#include +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif // __BORLANDC__ +//#include +#else // !_WIN32 +#if defined(UNIX) || defined(UNIV_LINUX) +#include +#include +//#if !defined(sun) // Sun has the ftruncate fnc. +//#define USETEMP // Force copy mode for DELETE +//#endif // !sun +#else // !UNIX +#include +#endif // !UNIX +#include +#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) + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(g->Message), MSG(NOT_FIXED_LEN), To_File, len, Lrecl); + + } else { + if (!(len % Lrecl)) + card = len / (int)Lrecl; // Fixed length file + else + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(g->Message), MSG(READ_ERROR), To_File, _strerror(NULL)); +#else + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(g->Message), MSG(READ_ERROR), To_File, _strerror(NULL)); +#else + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), MSG(FPUTS_ERROR), strerror(errno)); + return RC_FX; + } // endif EOF + + if (Tdbp->Mode == MODE_UPDATE && moved) + if (fseek(Stream, curpos, SEEK_SET)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(g->Message), MSG(CHSIZE_ERROR), strerror(errno)); + close(h); + return RC_FX; + } // endif +#else + if (ftruncate(h, (off_t)Tpos)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), MSG(DEL_READ_ERROR), (int) req, (int) len); + return true; + } // endif len + + if (!UseTemp) + if (fseek(T_Stream, Tpos, SEEK_SET)) { + snprintf(g->Message, sizeof(g->Message), MSG(WRITE_SEEK_ERR), strerror(errno)); + return true; + } // endif + + if ((len = fwrite(DelBuf, 1, req, T_Stream)) != req) { + snprintf(g->Message, sizeof(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, sizeof(g->Message), MSG(RENAME_ERROR), + filename, filetemp, strerror(errno)); + throw 51; + } else if (rename(tempname, filename)) { + snprintf(g->Message, sizeof(g->Message), MSG(RENAME_ERROR), + tempname, filename, strerror(errno)); + rc = rename(filetemp, filename); // Restore saved file + throw 52; + } else if (remove(filetemp)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(g->Message), MSG(READ_ERROR), To_File, _strerror(NULL)); +#else + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), MSG(FWRITE_ERROR), strerror(errno)); + return RC_FX; + } // endif fwrite + + if (moved) + if (fseek(Stream, curpos, SEEK_SET)) { + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(g->Message), MSG(READ_ERROR), To_File, _strerror(NULL)); +#else + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), "Error %d writing prefix to %s", + errno, To_File); + return RC_FX; + } else if (fwrite(To_Buf, Recsize, 1, T_Stream) != 1) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(g->Message), MSG(CHSIZE_ERROR), strerror(errno)); + close(h); + return RC_FX; + } // endif +#else + if (ftruncate(h, (off_t)Tpos)) { + snprintf(g->Message, sizeof(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..76e9336d --- /dev/null +++ b/storage/connect/filamvct.cpp @@ -0,0 +1,4327 @@ +/*********** 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 +#include +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif // __BORLAND__ +//#include +#include +#else // !_WIN32 +#if defined(UNIX) +#include +#include +#include +#include +#define NO_ERROR 0 +#else // !UNIX +#include +#endif // !UNIX +#include +#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++) { + snprintf(filename, _MAX_PATH, 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) { + snprintf(g->Message, sizeof(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) + { + PlugRemoveType(filename, filename); + strncat(filename, ".blk", _MAX_PATH - strlen(filename)); + } + + 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)) { + snprintf(g->Message, sizeof(g->Message), "Error reading header file %s", filename); + n = -1; + } else if (MaxBlk * Nrec != vh.MaxRec) { + snprintf(g->Message, sizeof(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 + PlugRemoveType(filename, filename); + strncat(filename, ".blk", _MAX_PATH - strlen(filename)); + s= global_fopen(g, MSGID_CANNOT_OPEN, filename, "wb"); + } // endif Header + + if (!s) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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(); + snprintf(filename, _MAX_PATH, 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 + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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) { + strncpy(g->Message, msg, sizeof(g->Message)); + 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) { + strncpy(g->Message, MSG(TRUNC_BY_ESTIM), sizeof(g->Message)); + 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)) { + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(g->Message), MSG(TRUNCATE_ERROR), strerror(errno)); + close(h); + return RC_FX; + } // endif +#else + if (chsize(h, Headlen + Block * Blksize)) { + snprintf(g->Message, sizeof(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()); + PlugRemoveType(tempname, tempname); + strncat(tempname, ".t", _MAX_PATH - strlen(tempname)); + + 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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(g->Message), MSG(WRITE_SEEK_ERR), strerror(errno)); + return true; + } // endif + + if ((len = fwrite(To_Buf, Clens[i], req, T_Stream)) != req) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(g->Message), MSG(WRITE_SEEK_ERR), strerror(errno)); + return true; + } // endif + + if ((len = fwrite(To_Buf, Clens[i], req, Stream)) != req) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(g->Message), MSG(WRITE_SEEK_ERR), strerror(errno)); + return true; + } // endif + + if ((len = fwrite(To_Buf, Clens[i], req, T_Stream)) != req) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(g->Message), MSG(BAD_READ_NUMBER), (int) n, To_File); + else + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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 { + strncpy(g->Message, "MAP Insert is for VEC Estimate tables only", sizeof(g->Message)); + 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)) + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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) { + strncpy(g->Message, msg, sizeof(g->Message)); + 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) { + strncpy(g->Message, MSG(TRUNC_BY_ESTIM), sizeof(g->Message)); + 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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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); + + snprintf(filename, _MAX_PATH, 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()); + PlugRemoveType(Tempat, Tempat); + strncat(Tempat, ".t", _MAX_PATH - strlen(Tempat)); + 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])) { + snprintf(g->Message, sizeof(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++) { + snprintf(filename, _MAX_PATH, 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]))) { + snprintf(g->Message, sizeof(g->Message), MSG(TRUNCATE_ERROR), strerror(errno)); + close(h); + return RC_FX; + } // endif +#else + if (chsize(h, Tpos * Clens[i])) { + snprintf(g->Message, sizeof(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. */ + /*****************************************************************/ + snprintf(tempname, _MAX_PATH, 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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(g->Message), MSG(WRITE_SEEK_ERR), strerror(errno)); + return true; + } // endif + + if ((len = fwrite(To_Buf, Clens[i], req, T_Streams[i])) != req) { + snprintf(g->Message, sizeof(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) { + snprintf(filename, _MAX_PATH, Colfn, i+1); + PlugSetPath(filename, filename, Tdbp->GetPath()); + PlugRemoveType(filetemp, filename); + strncat(filetemp, ".ttt", _MAX_PATH - strlen(filetemp)); + remove(filetemp); // May still be there from previous error + + if (rename(filename, filetemp)) { // Save file for security + snprintf(g->Message, sizeof(g->Message), MSG(RENAME_ERROR), + filename, filetemp, strerror(errno)); + rc = RC_FX; + } else if (rename(tempname, filename)) { + snprintf(g->Message, sizeof(g->Message), MSG(RENAME_ERROR), + tempname, filename, strerror(errno)); + rc = rename(filetemp, filename); // Restore saved file + rc = RC_FX; + } else if (remove(filetemp)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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]; + + snprintf(fn, _MAX_PATH, Colfn, colp->Index); +#if defined(_WIN32) + if (feof(Streams[i])) +#else // !_WIN32 + if (errno == NO_ERROR) +#endif // !_WIN32 + snprintf(g->Message, sizeof(g->Message), MSG(BAD_READ_NUMBER), (int) n, fn); + else + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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]; + + snprintf(fn, _MAX_PATH, (UseTemp) ? Tempat : Colfn, colp->Index); + snprintf(g->Message, sizeof(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); + + snprintf(filename, _MAX_PATH, 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)) + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(g->Message), MSG(SFP_ERROR), buf); + return true; + } // endif +#else // !_WIN32 + if (lseek64(h, pos, (b) ? SEEK_END : SEEK_SET) < 0) { + snprintf(g->Message, sizeof(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) + strncpy(buf, MSG(BAD_BYTE_READ), 256); + else { + drc = GetLastError(); + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0, + (LPTSTR)buf, sizeof(buf), NULL); + } // endelse brc + + snprintf(g->Message, sizeof(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"; + + snprintf(g->Message, sizeof(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) + strncpy(buf, MSG(BAD_BYTE_NUM), 256); + else { + drc = GetLastError(); + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0, + (LPTSTR)buf, sizeof(buf), NULL); + } // endelse brc + + snprintf(g->Message, sizeof(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"; + + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) + { + PlugRemoveType(filename, filename); + strncat(filename, ".blk", _MAX_PATH - strlen(filename)); + } + +#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))) { + snprintf(g->Message, sizeof(g->Message), "Error reading header file %s", filename); + n = -1; + } else if (MaxBlk * Nrec != vh.MaxRec) { + snprintf(g->Message, sizeof(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 + { + PlugRemoveType(filename, filename); + strncat(filename, ".blk", _MAX_PATH - strlen(filename)); + } + + 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) { + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(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(); + snprintf(g->Message, sizeof(g->Message), MSG(EMPTY_FILE), p, filename); + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0, + (LPTSTR)filename, sizeof(filename), NULL); + strncat(g->Message, filename, sizeof(g->Message) - strlen(g->Message)); + + 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: + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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(); + snprintf(g->Message, sizeof(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); + strncat(g->Message, filename, sizeof(g->Message) - strlen(g->Message)); + } // 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) { + snprintf(g->Message, sizeof(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; + strncpy(g->Message, MSG(NO_VCT_DELETE), sizeof(g->Message)); + break; + } // endif + + // Selective delete, pass thru + /* fall through */ + case MODE_UPDATE: + UseTemp = Tdbp->IsUsingTemp(g); + oflag = (UseTemp) ? O_RDONLY : O_RDWR; + break; + default: + snprintf(g->Message, sizeof(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; + snprintf(g->Message, sizeof(g->Message), MSG(OPEN_ERROR), rc, mode, filename); + strncat(g->Message, strerror(errno), sizeof(g->Message) - strlen(g->Message)); + } // 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) { + strncpy(g->Message, MSG(TRUNC_BY_ESTIM), sizeof(g->Message)); + 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(); + + snprintf(g->Message, sizeof(g->Message), MSG(SETEOF_ERROR), drc); + return RC_FX; + } // endif error +#else // !_WIN32 + if (ftruncate64(Hfile, (BIGINT)(Tpos * Lrecl))) { + snprintf(g->Message, sizeof(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()); + PlugRemoveType(tempname, tempname); + strncat(tempname, ".t", _MAX_PATH - strlen(tempname)); + + 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(); + snprintf(g->Message, sizeof(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); + strncat(g->Message, tempname, sizeof(g->Message) - strlen(g->Message)); + 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; + snprintf(g->Message, sizeof(g->Message), MSG(OPEN_ERROR), rc, MODE_INSERT, tempname); + strncat(g->Message, strerror(errno), sizeof(g->Message) - strlen(g->Message)); + 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..f0ee947b --- /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 +#include +#include +#include +#else // !UNIX +#include +#endif // !UNIX +#include +#endif // !_WIN32 +#include + +/***********************************************************************/ +/* 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"))) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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))) + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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))) + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), "Target file %s not in %s", target, fn); + return true; + } else if (rc != UNZ_OK) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), "unzGetCurrentFileInfo64 rc=%d", rc); + return true; + } else if ((rc = unzOpenCurrentFilePassword(zipfile, pwd)) != UNZ_OK) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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..da418d38 --- /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 +#else // !_WIN32 +#include +#include +#include +#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: + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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()) { +// snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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 + +#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 +#ifndef _WIN32 +#include +#endif + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include +#include + +/* 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 +#include +#endif /* UNIX */ +#include +#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 +#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/global.h b/storage/connect/global.h new file mode 100644 index 00000000..bc1585eb --- /dev/null +++ b/storage/connect/global.h @@ -0,0 +1,232 @@ +/***********************************************************************/ +/* 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 manipulation declares */ +#include /* C standard library */ +#include /* C language specific types */ +#include /* FOPEN_MAX declaration */ +#include /* time_t type declaration */ +#include /* Long jump declarations */ + +#define ROUNDUP_TO_8(num) (((num + 7) / 8) * 8) + +#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 : "") +#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..7be82db2 --- /dev/null +++ b/storage/connect/ha_connect.cc @@ -0,0 +1,7546 @@ +/* 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:
./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:
+ CREATE TABLE (...) 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 +#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 +#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 char *strz(PGLOBAL g, LEX_CSTRING &ls); +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, ""); + +// 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) +{ + return "english"; +} // 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(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(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 : ""); + + 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 : "", + 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(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); + PPOOLHEADER pph = (PPOOLHEADER)xp->g->Sarea; + snprintf(sv, xp->g->Sarea_Size - pph->To_Free, 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->cs_name.str; + + } 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()->coll_name.str; + + 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. + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(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(); + + snprintf(buf, sizeof(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: + snprintf(g->Message, sizeof(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) { + uint var_length= uint2korr(ptr); + String varchar((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* arglist= cond_item->argument_list(); + List_iterator 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* arglist= cond_item->argument_list(); + List_iterator 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; + char buf[MAX_FIELD_WIDTH]; + String strColumn(buf, sizeof(buf), system_charset_info); + 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 (tty == TYPE_AM_MYSQL && !(x || ismul)) + { + strColumn.length(0); + strColumn.qs_append(STRING_WITH_LEN("`")); + strColumn.qs_append(fnm, strlen(fnm)); + strColumn.append(STRING_WITH_LEN("`")); + } + + 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 + if (tty == TYPE_AM_MYSQL && !(x || ismul)) + strcat((ishav ? havg : body), strColumn.ptr()); + else + 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).lex_cstring()); + } else + buf->append(STRING_WITH_LEN("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) { + snprintf(g->Message, sizeof(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()) { + snprintf(g->Message, sizeof(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, strlen(field_name)); + error|= sql->append(STRING_WITH_LEN("` ")); + error|= sql->append(type, strlen(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(STRING_WITH_LEN(" UNSIGNED")); + else if (v == 'Z') + error |= sql->append(STRING_WITH_LEN(" ZEROFILL")); + + if (key && *key) { + error |= sql->append(' '); + error |= sql->append(key, strlen(key)); + } // endif key + + if (tm) + error |= sql->append(STRING_WITH_LEN(" NOT NULL"), system_charset_info); + + if (dft && *dft) { + error |= sql->append(STRING_WITH_LEN(" DEFAULT ")); + + if (typ == TYPE_DATE) + q = (strspn(dft, "0123456789 -:/") == strlen(dft)); + else + q = !IsTypeNum(typ); + + if (q) { + error |= sql->append(STRING_WITH_LEN("'")); + error |= sql->append_for_single_quote(dft, strlen(dft)); + error |= sql->append('\''); + } else + error |= sql->append(dft, strlen(dft)); + + } // endif dft + + if (xtra && *xtra) { + error |= sql->append(' '); + error |= sql->append(xtra, strlen(xtra)); + } // endif rem + + if (rem && *rem) { + error |= sql->append(STRING_WITH_LEN(" COMMENT '")); + error |= sql->append_for_single_quote(rem, strlen(rem)); + error |= sql->append(STRING_WITH_LEN("'")); + } // endif rem + + if (fmt && *fmt) { + switch (ttp) { + case TAB_MONGO: + case TAB_BSON: + case TAB_JSON: error |= sql->append(STRING_WITH_LEN(" JPATH='")); break; + case TAB_XML: error |= sql->append(STRING_WITH_LEN(" XPATH='")); break; + default: error |= sql->append(STRING_WITH_LEN(" FIELD_FORMAT='")); + } // endswitch ttp + + error |= sql->append_for_single_quote(fmt, strlen(fmt)); + error |= sql->append('\''); + } // endif flag + + if (flag) { + error |= sql->append(STRING_WITH_LEN(" 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, strlen(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, strlen(opt->name)); + oom|= sql->append(STRING_WITH_LEN("='")); + 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, strlen(opt->name)); + oom|= sql->append('='); + if (vull) + oom|= sql->append("YES", 3); + else + oom|= sql->append("NO", 2); + } // 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(STRING_WITH_LEN("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(STRING_WITH_LEN("CHARSET=")); + oom|= sql->append(create_info->default_table_charset->cs_name); + + 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); + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(g->Message), "Missing %s file name", topt->type); + else if (sep && strlen(sep) > 1) + snprintf(g->Message, sizeof(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))) + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(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) + sprintf(g->Message, "Missing %s HTTP address", topt->type); + else + ok= true; + + break; +#endif // REST_SUPPORT + case TAB_VIR: + ok= true; + break; + default: + snprintf(g->Message, sizeof(g->Message), "Cannot get column info for table type %s", topt->type); + break; + } // endif ttp + + // Check for supported catalog function + if (ok && !(supfnc & fnc)) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(g->Message), "Cannot get columns from %s", tab); + else + strncpy(g->Message, "Fail to retrieve columns", sizeof(g->Message)); + + 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))) { + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(g->Message), "Column %s skipped (unsupported type %d)", + cnm, typ); + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message); + continue; + } else { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(g->Message), "Column %s skipped (unsupported type %d)", + cnm, typ); + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message); + continue; + } else { + snprintf(g->Message, sizeof(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; + myf utf8_flag= thd->get_utf8_flag(); +#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); + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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(utf8_flag)))) { + 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))) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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)) + snprintf(g->Message, sizeof(g->Message), "DBF: Column name '%s' is too long (max=10)", + fp->field_name.str); + else if ((b= fp->field_length > 255)) + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(g->Message), "Default file %s already exists", fn); + else + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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()) { + snprintf(tfn, sizeof(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]; + + snprintf(buf, sizeof(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_INDEX_ORDER; + + 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)) { + snprintf(g->Message, sizeof(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..71ceb797 --- /dev/null +++ b/storage/connect/ha_connect.h @@ -0,0 +1,579 @@ +/* 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 + +/* This is a hack for ASAN + * Libraries such as libxml2 and libodbc do not like being unloaded before + * exit and will show as a leak in ASAN with no stack trace (as the plugin + * has been unloaded from memory). + * + * The below is designed to trick the compiler into adding a "UNIQUE" symbol + * which can be seen using: + * readelf -s storage/connect/ha_connect.so | grep UNIQUE + * + * Having this symbol means that the plugin remains in memory after dlclose() + * has been called. Thereby letting the libraries clean up properly. + */ +#if defined(__SANITIZE_ADDRESS__) +__attribute__((__used__)) +inline int dummy(void) +{ + static int d; + d++; + return d; +} +#endif diff --git a/storage/connect/inihandl.cpp b/storage/connect/inihandl.cpp new file mode 100644 index 00000000..cd06f7fa --- /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 +//#include +#include +//#include commented this line out to compile for solaris +#include +#include +#include +#include +//#include +//#include +#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 : "") +#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 + 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 = §ion->next; + next_key = §ion->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..1f339982 --- /dev/null +++ b/storage/connect/ioapi.c @@ -0,0 +1,247 @@ +/* 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(IOAPI_NO_64) +#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..44430e56 --- /dev/null +++ b/storage/connect/ioapi.h @@ -0,0 +1,210 @@ +/* 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(__linux__) + + // 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 +#include +#include "zlib.h" + +#if defined(USE_FILE32API) +#define fopen64 fopen +#define ftello64 ftell +#define fseeko64 fseek +#else +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__OpenBSD__) || defined(__DragonFly__) +#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 + #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..bf104402 --- /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 +//#include +#if defined(_WIN32) +#include // for getcwd +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif // __BORLANDC__ +#else // !_WIN32 +#if defined(UNIX) +#include +#else // !UNIX +#endif // !UNIX +#include +#include // 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(); + + snprintf(g->Message, sizeof(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"))) { + snprintf(g->Message, sizeof(g->Message), MSG(PROCADD_ERROR), GetLastError(), "JNI_CreateJavaVM"); + FreeLibrary((HMODULE)LibJvm); + LibJvm = NULL; + } else if (!(GetCreatedJavaVMs = (GETJVM)GetProcAddress((HINSTANCE)LibJvm, + "JNI_GetCreatedJavaVMs"))) { + snprintf(g->Message, sizeof(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"))) { + snprintf(g->Message, sizeof(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(); + snprintf(g->Message, sizeof(g->Message), MSG(SHARED_LIB_ERR), soname, SVP(error)); + } else if (!(CreateJavaVM = (CRTJVM)dlsym(LibJvm, "JNI_CreateJavaVM"))) { + error = dlerror(); + snprintf(g->Message, sizeof(g->Message), MSG(GET_FUNC_ERR), "JNI_CreateJavaVM", SVP(error)); + dlclose(LibJvm); + LibJvm = NULL; + } else if (!(GetCreatedJavaVMs = (GETJVM)dlsym(LibJvm, "JNI_GetCreatedJavaVMs"))) { + error = dlerror(); + snprintf(g->Message, sizeof(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(); + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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, "", "(Z)V"); + + if (ctor == nullptr) { + snprintf(g->Message, sizeof(g->Message), "ERROR: %s constructor not found!", m_Wrap); + return true; + } else + job = env->NewObject(jdi, ctor, jt); + + if (job == nullptr) { + snprintf(g->Message, sizeof(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 + +/***********************************************************************/ +/* 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..0ba1f56a --- /dev/null +++ b/storage/connect/jdbconn.cpp @@ -0,0 +1,1691 @@ +/************ 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 +#include +#if defined(_WIN32) +//nclude +//nclude +#include // for getcwd +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif // __BORLANDC__ +//#include +#else // !_WIN32 +#if defined(UNIX) +#include +#else // !UNIX +//nclude +#endif // !UNIX +#include +#include // for getenv +//nclude +#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()); + + /* fall 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(); + + /* fall through */ + case -9: // NVARCHAR (unicode) + // Postgresql can return this when size is unknown + if (len == 0x7FFFFFFF) + len = GetConvSize(); + + v = 'V'; + /* fall 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 + + /* fall 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 + size_t sqry_size = strlen(src) + 2; + sqry = (char*)PlugSubAlloc(g, NULL, sqry_size); + // Function PlugSubAlloc(...) recalculate string size + // while allocate memory - it rounds size up size to multiple of 8 + // we need to know the real allocated size + // to use it in sprintf(...) + const int sqry_real_allocated_size = ROUNDUP_TO_8(sqry_size); + snprintf(sqry, sqry_real_allocated_size, 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)) { + snprintf(g->Message, sizeof(g->Message), "%s: %s", fnc, Msg); + goto err; + } // endif Check + + rc = env->CallBooleanMethod(job, readid); + + if (Check(rc)) { + snprintf(g->Message, sizeof(g->Message), "ReadNext: %s", Msg); + goto err; + } else if (rc == 0) { + snprintf(g->Message, sizeof(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)) { + // snprintf(g->Message, sizeof(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) +{ + 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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(g->Message), "Execute: %s", Msg); + return RC_FX; + } // endif n + + m_Ncol = env->CallIntMethod(job, grs); + + if (Check(m_Ncol)) { + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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); + /* fall through */ + default: + val->Reset(); + } // endswitch Type + + chk: + if (Check()) { + if (rank == 0) + env->DeleteLocalRef(jn); + + snprintf(g->Message, sizeof(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))) + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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)) + snprintf(g->Message, sizeof(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, "", "(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: + snprintf(g->Message, sizeof(g->Message), "Parm type %d not supported", val->GetType()); + return true; + } // endswitch Type + + if (Check(jrc)) { + snprintf(g->Message, sizeof(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()) + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(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 +//#include +//#include +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif // __BORLANDC__ +//#include +#else // !_WIN32 +#if defined(UNIX) || defined(UNIV_LINUX) +//#include +#include +//#if !defined(sun) // Sun has the ftruncate fnc. +//#define USETEMP // Force copy mode for DELETE +//#endif // !sun +#else // !UNIX +//#include +#endif // !UNIX +//#include +#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..f527eb83 --- /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 + +/***********************************************************************/ +/* 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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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, "", "(I)V"); + val = env->NewObject(cls, cns, valp->GetIntValue()); + break; + case TYPE_TINY: + cls = env->FindClass("java/lang/Boolean"); + cns = env->GetMethodID(cls, "", "(Z)V"); + val = env->NewObject(cls, cns, (valp->GetIntValue() != 0)); + break; + case TYPE_BIGINT: + cls = env->FindClass("java/lang/Long"); + cns = env->GetMethodID(cls, "", "(J)V"); + val = env->NewObject(cls, cns, valp->GetBigintValue()); + break; + case TYPE_DOUBLE: + cls = env->FindClass("java/lang/Double"); + cns = env->GetMethodID(cls, "", "(D)V"); + val = env->NewObject(cls, cns, valp->GetFloatValue()); + break; + default: + snprintf(g->Message, sizeof(g->Message), "Cannot make object from %d type", valp->GetType()); + error = true; + break; + } // endswitch Type + + } catch (...) { + snprintf(g->Message, sizeof(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)) + snprintf(g->Message, sizeof(g->Message), "ArrayAdd: %s", Msg); + else + snprintf(g->Message, sizeof(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)) + snprintf(g->Message, sizeof(g->Message), "CollInsert: %s", Msg); + else + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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..4078a038 --- /dev/null +++ b/storage/connect/json.cpp @@ -0,0 +1,2063 @@ +/*************** 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 + +/***********************************************************************/ +/* 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 + +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 + + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(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"))) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), "Unexpected ',' near %.*s",ARGS); + throw 1; + } else + level = 1; + + break; + case ']': + if (level == 1) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 { + snprintf(g->Message, sizeof(g->Message), "misplaced string near %.*s", ARGS); + throw 2; + } // endif level + + break; + case ':': + if (level == 1) { + jpp->Val = ParseValue(g, ++i); + level = 2; + } else { + snprintf(g->Message, sizeof(g->Message), "Unexpected ':' near %.*s", ARGS); + throw 2; + } // endif level + + break; + case ',': + if (level < 2) { + snprintf(g->Message, sizeof(g->Message), "Unexpected ',' near %.*s", ARGS); + throw 2; + } else + level = 0; + + break; + case '}': + if (level == 0 || level == 1) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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: + snprintf(buf, sizeof(buf), "%d", jvp->N); + return js->WriteStr(buf); + case TYPE_BINT: + snprintf(buf, sizeof(buf), "%lld", jvp->LLn); + return js->WriteStr(buf); + case TYPE_DBL: // dfp to limit to the default number of decimals + snprintf(buf, sizeof(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; + break; + case TYPE_INT: + N = valp->GetIntValue(); + DataType = TYPE_INTG; + break; + case TYPE_BIGINT: + LLn = valp->GetBigintValue(); + DataType = TYPE_BINT; + break; + default: + snprintf(g->Message, sizeof(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 +#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..b09838be --- /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 +#include +#include +#include +#include + +#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 + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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; + snprintf(s, sizeof(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) { + snprintf(s, sizeof(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))) { + snprintf(g->Message, sizeof(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); + strmake(bsnp->Msg, bsnp->Filename, BMX-1); + } else + strmake(bsnp->Msg, "null filename", BMX-1); + + } else if (IsJson(args, 0) == 3) { + PBSON bsp = (PBSON)args->args[0]; + + if (bsp->Filename) { + bsnp->Filename = bsp->Filename; + strmake(bsnp->Msg, bsp->Filename, BMX-1); + 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); + break; + case INT_RESULT: + memlen += sizeof(TYPVAL); + break; + case REAL_RESULT: + case DECIMAL_RESULT: + memlen += sizeof(TYPVAL); + 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 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)) + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), "Error %d opening %-.1024s", errno, fn); + return NULL; + } // endif h + + if ((len = _filelength(h)) < 0) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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))) + strmake(bsp->Msg, g->Message, BMX-1); + + // 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))) + strmake(bsp->Msg, g->Message, BMX-1); + + // 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))) + strmake(bsp->Msg, g->Message, BMX-1); + + // 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))) + strmake(bsp->Msg, g->Message, BMX-1); + + // 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))) + strmake(bsp->Msg, g->Message, BMX-1); + + // 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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(g->Message), "Error %d reading %zu 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) { + snprintf(g->Message, sizeof(g->Message), "Error %d writing %zu bytes to %s", + errno, sizeof(binszp), ofn); + str = strcpy(result, g->Message); + } else if (fwrite(jsp, *binszp, 1, fout) != 1) { + snprintf(g->Message, sizeof(g->Message), "Error %d writing %zu 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)) + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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"))) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 { + snprintf(g->Message, sizeof(g->Message), "misplaced string near %.*s", ARGS); + throw 3; + } // endif level + + break; + case ':': + AddBuff(s[i++]); + + if (level == 1) { + CopyValue(g); + level = 2; + } else { + snprintf(g->Message, sizeof(g->Message), "Unexpected ':' near %.*s", ARGS); + throw 3; + } // endif level + + break; + case ',': + AddBuff(s[i]); + + if (level < 2) { + snprintf(g->Message, sizeof(g->Message), "Unexpected ',' near %.*s", ARGS); + throw 3; + } else + level = 0; + + break; + case '}': + AddBuff(s[i]); + + if (level == 1) { + snprintf(g->Message, sizeof(g->Message), "Unexpected '}' near %.*s", ARGS); + throw 3; + } // endif level + + return; + case '\n': + case '\r': + case ' ': + case '\t': + break; + default: + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), "Unexpected ',' near %.*s", ARGS); + throw 2; + } else + level = 1; + + AddBuff(s[i]); + break; + case ']': + if (level == 1) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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..14e1e448 --- /dev/null +++ b/storage/connect/libdoc.cpp @@ -0,0 +1,1250 @@ +/******************************************************************/ +/* Implementation of XML document processing using libxml2 */ +/* Author: Olivier Bertrand 2007-2016 */ +/******************************************************************/ +#include "my_global.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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. */ +/******************************************************************/ +void XmlCleanupParserLib(void) + { + } // 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, "\n", Encoding); + fprintf(of, "\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)) { + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(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, "", 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 { + snprintf(g->Message, sizeof(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; + snprintf(g->Message, sizeof(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..fd85210a --- /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) + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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 +#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..903798bc --- /dev/null +++ b/storage/connect/maputil.cpp @@ -0,0 +1,200 @@ +#include "my_global.h" +#ifdef UNIX +#include "osutil.h" +#include +#include +#else /* WINDOWS */ +//#include +#include "osutil.h" +#endif /* WINDOWS */ +#include +#include + +#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: + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), MSG(FILE_MAP_ERROR), filename, ler); + CloseHandle(hFile); + return INVALID_HANDLE_VALUE; + } else { + snprintf(g->Message, sizeof(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(); + + snprintf(g->Message, sizeof(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 +#include +#include +#include +#include + +/***********************************************************************/ +/* 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: + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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..91e04f3d --- /dev/null +++ b/storage/connect/messages.h @@ -0,0 +1,5 @@ +/**************************************************************************/ +/* NLS messsages definition. */ +/**************************************************************************/ +#include "engmsg.h" +/* ---------------------------------------------------------------------- */ 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 + +/***********************************************************************/ +/* 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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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..c4c2ade7 --- /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 + +#if defined(UNIX) +#include +#include +#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: + snprintf(g->Message, sizeof(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..4c16a7fc --- /dev/null +++ b/storage/connect/myconn.cpp @@ -0,0 +1,1096 @@ +/************** 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 +#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: + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(g->Message), "Column %s skipped (unsupported type %s)", + colname, buf); + PushWarning(g, thd); + continue; + } // endif v + + snprintf(g->Message, sizeof(g->Message), "Column %s unsupported type %s", colname, buf); + myc.Close(); + return NULL; + } else if (type == TYPE_STRING) { + if (v == 'X') { + len = GetConvSize(); + snprintf(g->Message, sizeof(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; + const char *p; + + if (!port) + port = mysqld_port; + + if (!strnicmp(srcdef, "select ", 7) || strstr(srcdef, "%s")) { + query = (char *)PlugSubAlloc(g, NULL, strlen(srcdef) + 10); + + if ((p= strstr(srcdef, "%s"))) + { + /* Replace %s with 1=1 */ + sprintf(query, "%.*s1=1%s", (int) (p - srcdef), srcdef, p + 2); // 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) + snprintf(g->Message, sizeof(g->Message), "mysql_real_connect failed: (%d) %s", + mysql_errno(m_DB), mysql_error(m_DB)); +#else // !_DEBUG + snprintf(g->Message, sizeof(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)))) { + + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(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, "MariaDB not connected"); + return RC_FX; + } else + assert(m_Stmt); + +#if defined(ALPHA) + if (mysql_bind_param(m_Stmt, bind)) { + snprintf(g->Message, sizeof(g->Message), "mysql_bind_param() failed: %s", + mysql_stmt_error(m_Stmt)); +#else // !ALPHA + if (mysql_stmt_bind_param(m_Stmt, bind)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(g->Message), "mysql_execute() failed: %s", + mysql_stmt_error(m_Stmt)); + return RC_FX; + } // endif execute +#else // !ALPHA + if (mysql_stmt_execute(m_Stmt)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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; + snprintf(g->Message, sizeof(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*)""; + } 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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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 +#else // !_WIN32 +#include +#endif // !_WIN32 +#include +#include +#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 ':'. +# +# : BUG# +# +# 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..09f4584a --- /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 Ignored +t1 1 xc 1 c A NULL NULL NULL XINDEX NO +t1 1 xd 1 d A NULL NULL NULL XINDEX NO +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 Ignored +# +# 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 COLLATE=latin1_swedish_ci +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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci +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 Ignored +t1 1 xc 1 c A NULL NULL NULL BTREE NO +t1 1 xd 1 d A NULL NULL NULL BTREE NO +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 COLLATE=latin1_swedish_ci `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 Ignored +t1 1 xc 1 c A NULL NULL NULL XINDEX NO +t1 1 xd 1 d A NULL NULL NULL XINDEX NO +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 Ignored +t1 1 xc 1 c A NULL NULL NULL XINDEX NO +t1 1 xd 1 d A NULL NULL NULL XINDEX NO +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 Ignored +# +# 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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci 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 COLLATE=latin1_swedish_ci 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 COLLATE=latin1_swedish_ci 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..65ad40d8 --- /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 COLLATE=latin1_swedish_ci `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 + + + + + + + + + 1 + One + + + 2 + Two + + + 3 + Three + + +# 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 COLLATE=latin1_swedish_ci `QUOTED`=1 `TABLE_TYPE`=XML `TABNAME`=t1 `OPTION_LIST`='xmlsup=domdoc,rownode=row' `HEADER`=0 +SELECT * FROM t2; +line + + + + + 1 + + + 2 + + + 3 + + +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..88359e4b --- /dev/null +++ b/storage/connect/mysql-test/connect/r/alter_xml2.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=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 COLLATE=latin1_swedish_ci `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 + + + + + + + + + 1 + One + + + 2 + Two + + + 3 + Three + + +# 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 COLLATE=latin1_swedish_ci `QUOTED`=1 `TABLE_TYPE`=XML `TABNAME`=t1 `OPTION_LIST`='xmlsup=libxml2,rownode=row' `HEADER`=0 +SELECT * FROM t2; +line + + + + + 1 + + + 2 + + + 3 + + +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..14808745 --- /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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci `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..a9567fe4 --- /dev/null +++ b/storage/connect/mysql-test/connect/r/bson.result @@ -0,0 +1,541 @@ +# +# 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 Ignored +t1 1 IX 1 ISBN A NULL NULL NULL XINDEX NO +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; +# +# MDEV-29426 memory leak on "SHOW INDEX" +# +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 Ignored +t1 1 IX 1 ISBN A NULL NULL NULL XINDEX NO +DROP TABLE t1; 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..4fc82698 --- /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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci `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..65d894a0 --- /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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci `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..d13d2a45 --- /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 COLLATE=latin1_swedish_ci `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..4b8806c1 --- /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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci `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..ef023b7c --- /dev/null +++ b/storage/connect/mysql-test/connect/r/general.result @@ -0,0 +1,32 @@ +# +# 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; +# +# MDEV-23626: CONNECT VIR tables return inconsistent error for UPDATE +# +CREATE TABLE numbers +ENGINE=CONNECT, +TABLE_TYPE=VIR, +BLOCK_SIZE=3; +TRUNCATE TABLE numbers; +ERROR HY000: Got error 174 'Virtual tables are read only' from CONNECT +DELETE FROM numbers WHERE n = 1; +ERROR HY000: Got error 174 'Virtual tables are read only' from CONNECT +UPDATE numbers SET n = 10 WHERE n = 1; +ERROR HY000: Got error 174 'Virtual tables are read only' from CONNECT +DROP TABLE numbers; 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..4999b76f --- /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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci `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..6abc576f --- /dev/null +++ b/storage/connect/mysql-test/connect/r/infoschema2-9739.result @@ -0,0 +1,8 @@ +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..86d25c8d --- /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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci `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..bec1dc87 --- /dev/null +++ b/storage/connect/mysql-test/connect/r/jdbc_postgresql.result @@ -0,0 +1,74 @@ +SET GLOBAL connect_class_path='C:/MariaDB-10.0/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..55b1bb8b --- /dev/null +++ b/storage/connect/mysql-test/connect/r/json.result @@ -0,0 +1,541 @@ +# +# 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 Ignored +t1 1 IX 1 ISBN A NULL NULL NULL XINDEX NO +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; +# +# MDEV-29426 memory leak on "SHOW INDEX" +# +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 Ignored +t1 1 IX 1 ISBN A NULL NULL NULL XINDEX NO +DROP TABLE t1; 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/misc.result b/storage/connect/mysql-test/connect/r/misc.result new file mode 100644 index 00000000..6b6372f6 --- /dev/null +++ b/storage/connect/mysql-test/connect/r/misc.result @@ -0,0 +1,54 @@ +execute immediate concat('create table t engine=CONNECT table_type=JSON',REPEAT('1',5000), +' FILE_NAME=''users.json'' HTTP=''http://localhost:4142'' URI=''/users'''); +ERROR HY000: Unsupported table type JSON1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +execute immediate concat('create table t engine=CONNECT table_type=OEM module=''libname'' +Option_list=''Myopt=foo'' subtype=''MYTYPE',REPEAT('1', 10000), ''''); +ERROR HY000: Subtype string too long +execute immediate concat('create table t engine=CONNECT table_type=DBF file_name=''', +REPLACE(@@secure_file_priv,'\\','/'),'cust.dbf', REPEAT('1', 10000), ''''); +ERROR HY000: Cannot open +create table t engine=connect table_type=mysql +CONNECTION='mysql://root@localhost:MASTER_MYPORT/test/foobar' + SRCDEF='SELECT 1,''%n'' FROM DUAL WHERE %s'; +select *from t; +ERROR HY000: Got error 174 'MakeSQL: Wrong place holders specification' from CONNECT +drop table t; +create table t engine=connect table_type=mysql +CONNECTION='mysql://root@localhost:MASTER_MYPORT/test/foobar' + SRCDEF='SELECT 1,%n FROM DUAL WHERE %s'; +ERROR HY000: (1064) You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '%n FROM DUAL WHERE 1=1 LIMIT 0' at line 1 [SELECT 1,%n FROM DUAL WHERE 1=1 LIMIT 0] +create table t engine=connect table_type=mysql +CONNECTION='mysql://root@localhost:MASTER_MYPORT/test/foobar' + SRCDEF='SELECT 1 FROM DUAL WHERE %s'; +select *from t; +1 +1 +drop table t; +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='MYSQLTEST_VARDIR/tmp/beer.xml' +tabname='table' option_list='rownode=tr,colnode=td%n'; +select * from beers; +Name Origin Description +NULL NULL NULL +NULL NULL NULL +drop table beers; +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='MYSQLTEST_VARDIR/tmp/beer.xml' +tabname='table' option_list='rownode=tr,colnode=td'; +insert into beers values('11','22','33'); +drop table beers; +execute immediate CONCAT('create table jsampall +(Author char(128) jpath=''$.AUTHOR["', REPEAT('a',10000),'"]'') +engine=CONNECT table_type=JSON +file_name=''',REPLACE(@@secure_file_priv,'\\','/'),'tmp/test.json'''); +select author from jsampall; +author +Jean-Christophe Bernadacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +William J. Pardi +drop table jsampall; 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..918256ac --- /dev/null +++ b/storage/connect/mysql-test/connect/r/mysql.result @@ -0,0 +1,330 @@ +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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` smallint(6) DEFAULT NULL +) ENGINE=CONNECT DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` int(9) DEFAULT NULL +) ENGINE=CONNECT DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` int(11) DEFAULT NULL +) ENGINE=CONNECT DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` bigint(20) DEFAULT NULL +) ENGINE=CONNECT DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` char(10) DEFAULT NULL +) ENGINE=CONNECT DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` varchar(10) DEFAULT NULL +) ENGINE=CONNECT DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` date DEFAULT NULL +) ENGINE=CONNECT DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci 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 COLLATE=latin1_swedish_ci CONNECTION='mysql://root@localhost:PORT/test/t1' `TABLE_TYPE`='MYSQL' +SELECT * FROM t2; +a +10 +20 +30 +DROP TABLE t2; +DROP TABLE t1; +# +# MDEV-27766 CONNECT Engine Support for INSERT IGNORE with Mysql Table type +# +CREATE TABLE t1 (a INT PRIMARY KEY); +INSERT INTO t1 VALUES (10),(20),(30); +CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL CONNECTION='mysql://root@localhost:PORT/test/t1' OPTION_LIST="Delayed=1,Ignored=1"; +INSERT INTO t2 VALUES (10),(20),(30),(40); +DROP TABLE t2; +DROP TABLE t1; +# +# MDEV-28533 CONNECT engine does not quote columns involved in WHERE clause +# +CREATE TABLE t1 (id int, `spaced col` varchar(10),`nospace` varchar(10)); +insert into t1 values (1,1,'x1'),(2,'C-003','x2'); +SELECT * from t1; +id spaced col nospace +1 1 x1 +2 C-003 x2 +CREATE TABLE t2 (id int, `spaced col` varchar(10), `nospace` varchar(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL DBNAME='test' TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=PORT'; +SELECT * from t2; +id spaced col nospace +1 1 x1 +2 C-003 x2 +SELECT `id` FROM t2 WHERE t2.`nospace` = 'x1'; +id +1 +SELECT `id` FROM t2 WHERE t2.`spaced col` = 'C-003'; +id +2 +DROP TABLE t1; +DROP TABLE t2; +# +# End of 10.3 tests +# 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..1c9f83cd --- /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 COLLATE=latin1_swedish_ci 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..4d4006ee --- /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 COLLATE=latin1_swedish_ci 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 COLLATE=latin1_swedish_ci 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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci 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 COLLATE=latin1_swedish_ci +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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci +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 COLLATE=latin1_swedish_ci 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 COLLATE=latin1_swedish_ci +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 COLLATE=latin1_swedish_ci 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..442fe36a --- /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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci 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 COLLATE=latin1_swedish_ci 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..6bd8d75a --- /dev/null +++ b/storage/connect/mysql-test/connect/r/odbc_postgresql.result @@ -0,0 +1,321 @@ +Table Create Table +t1 CREATE TABLE `t1` ( + `Name` varchar(256) NOT NULL, + `Description` varchar(256) DEFAULT NULL +) ENGINE=CONNECT DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci `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 space_in_column_name TABLE +mtr schema1 t1 TABLE +mtr schema1 t2 TABLE +mtr schema1 t3 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 space_in_column_name TABLE +mtr schema1 t1 TABLE +mtr schema1 t2 TABLE +mtr schema1 t3 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 space_in_column_name TABLE +mtr schema1 t1 TABLE +mtr schema1 t2 TABLE +mtr schema1 t3 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 space_in_column_name my space column 1 bpchar 20 80 NULL NULL 0 +mtr schema1 t1 a 1 bpchar 10 40 NULL NULL 0 +mtr schema1 t2 a 1 bpchar 10 40 NULL NULL 0 +mtr schema1 t3 a 1 bpchar 10 40 NULL NULL 0 +mtr schema1 t3 b 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 space_in_column_name my space column 1 bpchar 20 80 NULL NULL 0 +mtr schema1 t1 a 1 bpchar 10 40 NULL NULL 0 +mtr schema1 t2 a 1 bpchar 10 40 NULL NULL 0 +mtr schema1 t3 a 1 bpchar 10 40 NULL NULL 0 +mtr schema1 t3 b 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 COLLATE=latin1_swedish_ci 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 COLLATE=latin1_swedish_ci +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 COLLATE=latin1_swedish_ci 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 COLLATE=utf8_general_ci 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 COLLATE utf8_general_ci NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +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 COLLATE=utf8_general_ci 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 COLLATE utf8_general_ci DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +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 COLLATE=utf8_general_ci 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 COLLATE utf8_general_ci NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +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; +CREATE TABLE t1 (a VARCHAR(6), b VARCHAR(6), PRIMARY KEY(a, b)) ENGINE=CONNECT TABNAME='schema1.t3' CHARSET=utf8 DATA_CHARSET=utf8 TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr'; +DELETE FROM t1 WHERE a='20'; +Warnings: +Note 1105 schema1.t3: 0 affected rows +DROP TABLE t1; +# +# MDEV-29687 ODBC tables do not quote identifier names correctly +# +CREATE TABLE pg_in_maria ENGINE=CONNECT TABNAME='schema1.space_in_column_name' CHARSET=utf8 DATA_CHARSET=utf8 TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' quoted=1; +SELECT * from pg_in_maria; +my space column +My value +DROP TABLE pg_in_maria; 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..79a7cac0 --- /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 Ignored +t1 0 PRIMARY 1 id A NULL NULL NULL XINDEX NO +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 Ignored +t1 1 XID 1 id A NULL NULL NULL XINDEX NO +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 Ignored +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 Ignored +t1 0 PRIMARY 1 id A NULL NULL NULL XINDEX NO +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 Ignored +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..0cd4f011 --- /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 Ignored +t1 0 PRIMARY 1 id NULL NULL NULL NULL REMOTE NO +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..52c10b6c --- /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 COLLATE=latin1_swedish_ci `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 COLLATE=latin1_swedish_ci 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 COLLATE=latin1_swedish_ci 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 COLLATE=latin1_swedish_ci 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..d09e5318 --- /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 + + + + Jean-Christophe + Bernadac + + + François + Knab + + Construire une application XML + + Eyrolles + Paris + + 1999 + + + + William J. + Pardi + + + James + Guerin + + XML en Action + + Microsoft Press + Paris + + 1999 + + + Alain Michard + XML, Langage et Applications + Eyrolles Paris + 1998 + + + +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 COLLATE=latin1_swedish_ci `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) +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) +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) + + + + &<>"' + + + 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..3f82ed1a --- /dev/null +++ b/storage/connect/mysql-test/connect/r/xml2.result @@ -0,0 +1,398 @@ +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 + + + + Jean-Christophe + Bernadac + + + François + Knab + + Construire une application XML + + Eyrolles + Paris + + 1999 + + + + William J. + Pardi + + + James + Guerin + + XML en Action + + Microsoft Press + Paris + + 1999 + + + Alain Michard + XML, Langage et Applications + Eyrolles Paris + 1998 + + + +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 COLLATE=latin1_swedish_ci `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) +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) +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) + + + + ÀÃÂà + + + АБВГ + + + &<>"' + + + 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..e014f00f --- /dev/null +++ b/storage/connect/mysql-test/connect/r/xml2_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=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..0ec47ad8 --- /dev/null +++ b/storage/connect/mysql-test/connect/r/xml2_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=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..8913663f --- /dev/null +++ b/storage/connect/mysql-test/connect/r/xml2_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=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..5d68527b --- /dev/null +++ b/storage/connect/mysql-test/connect/r/xml2_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=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..7e36650d --- /dev/null +++ b/storage/connect/mysql-test/connect/r/xml2_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=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 Binary files /dev/null and b/storage/connect/mysql-test/connect/std_data/JavaWrappers.jar 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 Binary files /dev/null and b/storage/connect/mysql-test/connect/std_data/JdbcMariaDB.jar 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 Binary files /dev/null and b/storage/connect/mysql-test/connect/std_data/Mongo2.jar 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 Binary files /dev/null and b/storage/connect/mysql-test/connect/std_data/Mongo3.jar 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 Binary files /dev/null and b/storage/connect/mysql-test/connect/std_data/Testbal.dat 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 @@ + + +
cdcd
+ + + + + + + + + + + +
NameOriginDescription
HuntsmanBath, UK
Wonderful hop, light alcohol
TuborgDanmark
In small bottles
+ 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 @@ + + + + Everyday Italian + Giada De Laurentiis + 2005 + 30.00 + + + Harry Potter + J K. Rowling + 2005 + 29.99 + + + XQuery Kick Start + James McGovern + Per Bothner + Kurt Cagle + James Linn + Vaidyanathan Nagarajan + 2003 + 49.99 + + + Learning XML + Erik T. Ray + 2003 + 39.95 + + 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 @@ + + + + + + + + + + + + + + + + + + + + +
Cups of coffee consumed by each senator
NameCupsType of CoffeeSugar?
T. Sexton10EspressoNo
J. Dinnen5DecafYes
+ 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 Binary files /dev/null and b/storage/connect/mysql-test/connect/std_data/contacts.xls 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 @@ + +ÁÂÃÄÅÆÇ 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 @@ + +ÁÂÃÄÅÆÇ 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 Binary files /dev/null and b/storage/connect/mysql-test/connect/std_data/mdev9949.frm 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 @@ + +ÁÂÃÄÅÆÇ 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 Binary files /dev/null and b/storage/connect/mysql-test/connect/std_data/test.sqlite3 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 @@ + + + + + Jean-Christophe + Bernadac + + + François + Knab + + Construire une application XML + + Eyrolles + Paris + + 1999 + + + + William J. + Pardi + + + James + Guerin + + XML en Action + + Microsoft Press + Paris + + 1999 + + 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 @@ + + + + + Jean-Christophe + Bernadac + + + François + Knab + + Construire une application XML + + Eyrolles + Paris + + 1999 + + + + William J. + Pardi + + + James + Guerin + + XML en Action + + Microsoft Press + Paris + + 1999 + + + + Alain + Michard + + XML, Langage et Applications + + Eyrolles + Paris + + 2003 + + 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..173435d7 --- /dev/null +++ b/storage/connect/mysql-test/connect/t/bson.test @@ -0,0 +1,317 @@ +--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; + +--echo # +--echo # MDEV-29426 memory leak on "SHOW INDEX" +--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; +DROP TABLE t1; + +# +# 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..ca5124f1 --- /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..e2f22873 --- /dev/null +++ b/storage/connect/mysql-test/connect/t/general.test @@ -0,0 +1,33 @@ +--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; + +--echo # +--echo # MDEV-23626: CONNECT VIR tables return inconsistent error for UPDATE +--echo # + +CREATE TABLE numbers +ENGINE=CONNECT, +TABLE_TYPE=VIR, +BLOCK_SIZE=3; + +--error ER_GET_ERRMSG +TRUNCATE TABLE numbers; +--error ER_GET_ERRMSG +DELETE FROM numbers WHERE n = 1; +--error ER_GET_ERRMSG +UPDATE numbers SET n = 10 WHERE n = 1; +DROP TABLE numbers; 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..64722af0 --- /dev/null +++ b/storage/connect/mysql-test/connect/t/have_libxml2.inc @@ -0,0 +1,19 @@ +--disable_query_log +--disable_warnings +--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_warnings +--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..80306fc5 --- /dev/null +++ b/storage/connect/mysql-test/connect/t/json.test @@ -0,0 +1,318 @@ +--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; + + +--echo # +--echo # MDEV-29426 memory leak on "SHOW INDEX" +--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; +DROP TABLE t1; + +# +# 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/misc.test b/storage/connect/mysql-test/connect/t/misc.test new file mode 100644 index 00000000..5cfe2a8f --- /dev/null +++ b/storage/connect/mysql-test/connect/t/misc.test @@ -0,0 +1,142 @@ +--source have_libxml2.inc + +# Overlong table type +--error ER_UNKNOWN_ERROR +execute immediate concat('create table t engine=CONNECT table_type=JSON',REPEAT('1',5000), +' FILE_NAME=''users.json'' HTTP=''http://localhost:4142'' URI=''/users'''); + +# Overlong subtype +--error ER_UNKNOWN_ERROR +execute immediate concat('create table t engine=CONNECT table_type=OEM module=''libname'' +Option_list=''Myopt=foo'' subtype=''MYTYPE',REPEAT('1', 10000), ''''); + + +# Overlong filename +--error ER_UNKNOWN_ERROR +execute immediate concat('create table t engine=CONNECT table_type=DBF file_name=''', + REPLACE(@@secure_file_priv,'\\','/'),'cust.dbf', REPEAT('1', 10000), ''''); + + +# Format string in SRCDEF +--replace_result $MASTER_MYPORT MASTER_MYPORT +eval create table t engine=connect table_type=mysql + CONNECTION='mysql://root@localhost:$MASTER_MYPORT/test/foobar' + SRCDEF='SELECT 1,''%n'' FROM DUAL WHERE %s'; +--error ER_GET_ERRMSG +select *from t; +drop table t; + +--replace_result $MASTER_MYPORT MASTER_MYPORT +--error ER_UNKNOWN_ERROR +eval create table t engine=connect table_type=mysql + CONNECTION='mysql://root@localhost:$MASTER_MYPORT/test/foobar' + SRCDEF='SELECT 1,%n FROM DUAL WHERE %s'; + +--replace_result $MASTER_MYPORT MASTER_MYPORT +eval create table t engine=connect table_type=mysql + CONNECTION='mysql://root@localhost:$MASTER_MYPORT/test/foobar' + SRCDEF='SELECT 1 FROM DUAL WHERE %s'; +select *from t; +drop table t; + +write_file $MYSQLTEST_VARDIR/tmp/beer.xml; + + + + + + + + + + + + + + +
NameOriginDescription
HuntsmanBath, UK
Wonderful hop, light alcohol
TuborgDanmark
In small bottles
+
+EOF + +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +# Format string in colnode +eval 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='$MYSQLTEST_VARDIR/tmp/beer.xml' +tabname='table' option_list='rownode=tr,colnode=td%n'; +select * from beers; +drop table beers; + +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval 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='$MYSQLTEST_VARDIR/tmp/beer.xml' +tabname='table' option_list='rownode=tr,colnode=td'; +insert into beers values('11','22','33'); +drop table beers; + +remove_file $MYSQLTEST_VARDIR/tmp/beer.xml; + +write_file $MYSQLTEST_VARDIR/tmp/test.json; +[ + { + "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", + "TRANSLATED": { + "PREFIX": "adapté de l'anglais par", + "TRANSLATOR": { + "FIRSTNAME": "James", + "LASTNAME": "Guerin" + } + }, + "PUBLISHER": { + "NAME": "Microsoft Press", + "PLACE": "Paris" + }, + "DATEPUB": 1999 + } +] +EOF + +execute immediate CONCAT('create table jsampall +(Author char(128) jpath=''$.AUTHOR["', REPEAT('a',10000),'"]'') +engine=CONNECT table_type=JSON +file_name=''',REPLACE(@@secure_file_priv,'\\','/'),'tmp/test.json'''); + +select author from jsampall; +drop table jsampall; +remove_file $MYSQLTEST_VARDIR/tmp/test.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..25c3f207 --- /dev/null +++ b/storage/connect/mysql-test/connect/t/mongo.inc @@ -0,0 +1,11 @@ +#let $MONGO= C:/Applic/MongoDB/Server/3.6/bin/mongo; +#let $MONGOIMPORT= C:/Applic/MongoDB/Server/3.6/bin/mongoimport; +let $MONGO= mongo; +let $MONGOIMPORT= 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..ce76a466 --- /dev/null +++ b/storage/connect/mysql-test/connect/t/mysql.test @@ -0,0 +1,508 @@ +-- 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; + + +--echo # +--echo # MDEV-27766 CONNECT Engine Support for INSERT IGNORE with Mysql Table type +--echo # + +CREATE TABLE t1 (a INT PRIMARY KEY); +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' OPTION_LIST="Delayed=1,Ignored=1" +INSERT INTO t2 VALUES (10),(20),(30),(40); +DROP TABLE t2; +DROP TABLE t1; + +--echo # +--echo # MDEV-28533 CONNECT engine does not quote columns involved in WHERE clause +--echo # + +CREATE TABLE t1 (id int, `spaced col` varchar(10),`nospace` varchar(10)); +insert into t1 values (1,1,'x1'),(2,'C-003','x2'); + +SELECT * from t1; + +--replace_result $PORT PORT +--eval CREATE TABLE t2 (id int, `spaced col` varchar(10), `nospace` varchar(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL DBNAME='test' TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT' + +SELECT * from t2; +SELECT `id` FROM t2 WHERE t2.`nospace` = 'x1'; +SELECT `id` FROM t2 WHERE t2.`spaced col` = 'C-003'; + + +DROP TABLE t1; +DROP TABLE t2; + +--echo # +--echo # End of 10.3 tests +--echo # 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..9b22c69a --- /dev/null +++ b/storage/connect/mysql-test/connect/t/odbc_postgresql.sql @@ -0,0 +1,32 @@ +-- +-- The SQL script to create PostgreSQL data for odbc_postgresql.test +-- +-- Run this script as a admin user: +-- sudo -u postgres psql < storage/connect/mysql-test/connect/t/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 PRIVILEGES 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'),('ÄÖÜ'); +CREATE TABLE schema1.t3 (a CHAR(10) NOT NULL, b CHAR(10) NOT NULL); +INSERT INTO schema1.t3 VALUES ('xxx', 'aaa'),('yyy', 'bbb'),('zzz', 'ccc'),('ÄÖÜ', 'ÑÑÑ'); +CREATE TABLE schema1.space_in_column_name ("my space column" CHAR(20) NOT NULL); +INSERT INTO schema1.space_in_column_name VALUES ('My value'); +\dt schema1.* 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..ec98453d --- /dev/null +++ b/storage/connect/mysql-test/connect/t/odbc_postgresql.test @@ -0,0 +1,225 @@ +--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 start on the system startup +# +# 2. Create user, database, schema and tables to be used by mtr: +# sudo -u postgres psql < storage/connect/mysql-test/connect/t/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 or in ~/.odbc.ini +# +#[ConnectEnginePostgresql] +#Description=PostgreSQL DSN for ConnectSE +#Driver=PostgreSQL (should the path to the driver so file, on linux: /usr/lib/x86_64-linux-gnu/odbc/psqlodbca.so) +#Database=mtr +#Servername=localhost +#Port=5432 +# +# 5. Allow user "mtr" to connect to the database "mtr" +# Find `pg_hba.conf` file: +# Run `SHOW hba_file;` or `locate pg_hba.conf` to find right location +# (usually /var/lib/pgsql/data/pg_hba.conf or /etc/postgresql/[version]/main/pg_hba.conf on Linux) +# Add this line into the beginning of pg_hba.conf: +# For unix socket connection (connect with `psql -U mtr`) +#local mtr mtr password +# For TCP/IP connection (connect with `psql -U mtr -h 127.0.0.1`) +#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; + +# MDEV-25767 DELETE with WHERE condition crashes when two columns used for +# pkey +CREATE TABLE t1 (a VARCHAR(6), b VARCHAR(6), PRIMARY KEY(a, b)) ENGINE=CONNECT TABNAME='schema1.t3' CHARSET=utf8 DATA_CHARSET=utf8 TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr'; +DELETE FROM t1 WHERE a='20'; +DROP TABLE t1; + +--echo # +--echo # MDEV-29687 ODBC tables do not quote identifier names correctly +--echo # +CREATE TABLE pg_in_maria ENGINE=CONNECT TABNAME='schema1.space_in_column_name' CHARSET=utf8 DATA_CHARSET=utf8 TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' quoted=1; +SELECT * from pg_in_maria; +DROP TABLE pg_in_maria; 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 +#if defined(_WIN32) +//#include +#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..830a8494 --- /dev/null +++ b/storage/connect/noconst.c @@ -0,0 +1,38 @@ +/***********************************************************************/ +/* (C) Copyright to the author Olivier BERTRAND 2015 */ +/***********************************************************************/ +#include +#include +#include + +#if defined(_WIN32) +#define DllExport __declspec( dllexport ) +#else // !_WIN32 +#define DllExport +#endif // !_WIN32 + +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..09140712 --- /dev/null +++ b/storage/connect/odbconn.cpp @@ -0,0 +1,2654 @@ +/***********************************************************************/ +/* Name: ODBCONN.CPP Version 2.4 */ +/* */ +/* (C) Copyright to the author Olivier BERTRAND 1998-2021 */ +/* */ +/* This file contains the ODBC connection classes functions. */ +/***********************************************************************/ + +/***********************************************************************/ +/* Include relevant MariaDB header file. */ +/***********************************************************************/ +#include +#include +#if defined(_WIN32) +//nclude +//nclude +#include // for getcwd +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif +//#include +#else +#if defined(UNIX) +#include +#else +//nclude +#endif +//nclude +#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; + /* fall through */ + case SQL_VARCHAR: // 12 + v = 'V'; + type = TYPE_STRING; + break; + case SQL_WCHAR: // (-8) + w = true; + /* fall through */ + case SQL_CHAR: // 1 + type = TYPE_STRING; + break; + case SQL_WLONGVARCHAR: // (-10) + w = true; + /* fall through */ + 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] = '"'; + if (tdbp) + { + if (tdbp->Quoted && tdbp->Quote) + m_IDQuoteChar[0] = *tdbp->Quote; + } + 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(); + // Still we want to use the set QChar + } catch(DBX *xp) { + snprintf(g->Message, sizeof(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, k; + 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); + + k = 0; // used for column number + } // 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 (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 (m_Tdb->Srcdef) + k = colp->GetIndex(); + else + k++; + + if (trace(1)) + htrc("Binding col=%u type=%d buf=%p len=%d slen=%p\n", + k, tp, buffer, len, colp->GetStrLen()); + + rc = SQLBindCol(hstmt, k, tp, buffer, len, colp->GetStrLen()); + + if (!Check(rc)) + ThrowDBX(rc, "SQLBindCol", hstmt); + + } // endif colp + + } 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]); + + snprintf(g->Message, sizeof(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]); + + snprintf(g->Message, sizeof(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]); + + snprintf(g->Message, sizeof(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]); + + snprintf(g->Message, sizeof(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))) + snprintf(g->Message, sizeof(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))) + snprintf(g->Message, sizeof(g->Message), "SQLEndTran: rc=%d", rc); + + if (!Check(rc = SQLSetConnectAttr(m_hdbc, SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_IS_UINTEGER))) + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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"); + break; + 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) { + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(g->Message), MSG(NO_TABCOL_DATA), cap->Tab, cap->Pat); + else + snprintf(g->Message, sizeof(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]); + + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(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 include file */ +//nclude /* Message crackers */ + +/***********************************************************************/ +/* Included C-definition files required by the interface. */ +/***********************************************************************/ +#include "block.h" + +/***********************************************************************/ +/* ODBC interface. */ +/***********************************************************************/ +#include +#include + +/***********************************************************************/ +/* 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 +#include +#include +#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 +#include +#include +#include +#include + +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 +#include +#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 + +typedef __int64 FILEPOS; +//pedef HANDLE FILEHANDLE; // Win32 + +#endif /* WINDOWS */ + +#define XSTR(x) ((x)?(x):"") + + +#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..4371f90a --- /dev/null +++ b/storage/connect/plgdbsem.h @@ -0,0 +1,647 @@ +/************** 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. */ +/***********************************************************************/ +#define DEFAULT_LOCALE "English" + +#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..0f075a67 --- /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 +#include +#include +#define BIGMEM 1048576 // 1 Megabyte +#else // !_WIN32 +#include +#include +//#if defined(THREAD) +#include +//#endif // THREAD +#include +#define BIGMEM 2147483647 // Max int value +#endif // !_WIN32 +#include + +/***********************************************************************/ +/* 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)))) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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 of M */ +/* and each of M is part of exactly one substring. */ +/* */ +/* 2- If the i-th of P is an , the i-th subtring of M is any single . */ +/* */ +/* 3- If the i-th of P is an , then the i-th subtring of M is any sequence of zero */ +/* or more . */ +/* */ +/* 4- If the i-th of P is neither an nor an , then */ +/* the i-th substring of M is equal to that */ +/* according to the collating sequence of the , */ +/* without the appending of , and has the same */ +/* length as that . */ +/* */ +/* 5- The number of substrings of M is equal to the number of */ +/* 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 */ + b = (t || !*sp); /* true if % or void strg. */ + else if (!t) { + /*******************************************************************/ + /* No character to skip, check occurrence of */ + /* 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 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.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 */ + snprintf(g->Message, sizeof(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; + + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 include file */ +#include /* Message crackers */ +#include + +/***********************************************************************/ +/* Included C-definition files required by the interface. */ +/***********************************************************************/ +#include /* String manipulation declares */ +#include /* C standard library */ +#include /* C language specific types */ +#include /* FOPEN_MAX declaration */ +#include /* 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..d78ba120 --- /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 + snprintf(g->Message, sizeof(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..6fb40c92 --- /dev/null +++ b/storage/connect/plugutil.cpp @@ -0,0 +1,644 @@ +/************** 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 +#else +#if defined(UNIX) || defined(UNIV_LINUX) +#include +#include +//#define __stdcall +#else +#include +#endif +#include +#endif + +#if defined(WIN) +#include +#endif +#include /* definitions of ERANGE ENOMEM */ +#if !defined(UNIX) && !defined(UNIV_LINUX) +#include /* 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 (strlen(FileName) >= _MAX_PATH) + { + *pBuff= 0; /* Hope this is treated as error of some kind*/ + return FileName; + } + + 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"))) { + snprintf(stmsg, sizeof(stmsg), "Fail to open message file %s", msgfile); + goto err; + } // endif mfile + + for (;;) + if (!fgets(buff, 256, mfile)) { + snprintf(stmsg, sizeof(stmsg), "Cannot get message %d %s", 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)) { + snprintf(stmsg, sizeof(stmsg), "Bad message file for %d %s", 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(); + const int BUF_SIZE= 512; + msg = (char*)PlugSubAlloc(g, NULL, BUF_SIZE); // Extend buf allocation + n = snprintf(msg, BUF_SIZE, "Message %d, rc=%d: ", mid, rc); + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0, + (LPTSTR)(msg + n), BUF_SIZE - n, NULL); + return msg; + } // endif n + +#else // ALL + if (!GetRcString(mid, stmsg, 200)) + snprintf(stmsg, sizeof(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) { + snprintf(g->Message, sizeof(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 = ROUNDUP_TO_8(size); /* 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"; + + snprintf(g->Message, sizeof(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..e2fd08ba --- /dev/null +++ b/storage/connect/rcmsg.c @@ -0,0 +1,58 @@ +/**************** 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 +#include +#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 + 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..114071b3 --- /dev/null +++ b/storage/connect/reldef.cpp @@ -0,0 +1,955 @@ +/************* 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 +#else +//#include // 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 if (strlen(subtype)+1+3 >= sizeof(getname)) { + strcpy(g->Message, "Subtype string too long"); + 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(); + + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(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(); + snprintf(g->Message, sizeof(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(); + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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, + MYF(MY_UTF8_IS_UTF8MB3)): + 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 */ + snprintf(g->Message, sizeof(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(); + + snprintf(g->Message, sizeof(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(); + + snprintf(g->Message, sizeof(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(); + snprintf(g->Message, sizeof(g->Message), "dlopen failed: %s, OEM not supported", SVP(error)); + return NULL; + } // endif dlopen + + } else { + error = dlerror(); + snprintf(g->Message, sizeof(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(); + snprintf(g->Message, sizeof(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(); + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 +#include + +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(); + + 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 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..4cbb0e44 --- /dev/null +++ b/storage/connect/tabbson.cpp @@ -0,0 +1,2632 @@ +/************* 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 + +/***********************************************************************/ +/* 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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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->GetNext(jsp); + + 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)) { + snprintf(buf, sizeof(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: + snprintf(g->Message, sizeof(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] != ']') { + snprintf(g->Message, sizeof(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] != ']') { + snprintf(g->Message, sizeof(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: + snprintf(G->Message, sizeof(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: + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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 { + snprintf(g->Message, sizeof(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 + + snprintf(g->Message, sizeof(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: // ?????????? + snprintf(g->Message, sizeof(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; + Docrow = NULL; + Multiple = tdp->Multiple; + Docsize = 0; + Done = Changed = false; + Bp->SetPretty(2); +} // end of TDBBSON standard constructor + +TDBBSON::TDBBSON(PBTDB tdbp) : TDBBSN(tdbp) +{ + Docp = tdbp->Docp; + Docrow = tdbp->Docrow; + Multiple = tdbp->Multiple; + Docsize = tdbp->Docsize; + 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))) { + snprintf(g->Message, sizeof(g->Message), "Cannot find object key %s", key); + return RC_FX; + } // endif val + + } else { + if (*p == '[') { + // Old style + if (p[strlen(p) - 1] != ']') { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 + + Docsize = Bp->GetSize(Docp); + 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 = Docsize; + + } 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; + Docrow = NULL; + 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; + Docrow = NULL; + 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; + Docrow = NULL; + 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: + snprintf(g->Message, sizeof(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 < Docsize) { + Docrow = (Docrow) ? Bp->GetNext(Docrow) : Bp->GetArrayValue(Docp, Fpos); + Row = (Docrow->Type == TYPE_JVAL) ? Bp->GetBson(Docrow) : Docrow; + 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..1696f4df --- /dev/null +++ b/storage/connect/tabbson.h @@ -0,0 +1,344 @@ +/*************** 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 + PBVAL Docrow; // Document row + int Multiple; // 0: No 1: DIR 2: Section 3: filelist + int Docsize; // The document size + 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 + +/***********************************************************************/ +/* 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..62eecb5e --- /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 +#include // For testing only +#include +#include +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif // __BORLANDC__ +//#include +#else // !_WIN32 +#if defined(UNIX) +#include +#include +#else // !UNIX +#include +#endif // !UNIX +#include +#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: + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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"))) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), MSG(OPT_HEAD_WR_ERR), strerror(errno)); + rc = true; + } // endif size + + if (fwrite(Txfp->BlkPos, lg, block, opfile) != block) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), MSG(OPT_HEAD_WR_ERR), strerror(errno)); + rc = true; + } // endif size + + if (fwrite(colp->Dval->GetValPointer(), lg, ndv, opfile) != ndv) { + snprintf(g->Message, sizeof(g->Message), MSG(OPT_DVAL_WR_ERR), strerror(errno)); + rc = true; + } // endif size + + if (fwrite(colp->Bmap->GetValPointer(), sizeof(int), nbk, opfile) != nbk) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), MSG(OPT_HEAD_WR_ERR), strerror(errno)); + rc = true; + } // endif size + + if (fwrite(colp->Min->GetValPointer(), lg, block, opfile) != block) { + snprintf(g->Message, sizeof(g->Message), MSG(OPT_MIN_WR_ERR), strerror(errno)); + rc = true; + } // endif size + + if (fwrite(colp->Max->GetValPointer(), lg, block, opfile) != block) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), MSG(OPT_HEAD_RD_ERR), strerror(errno)); + goto err; + } // endif size + + if (n[1] != lg || n[2] != nrec) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), MSG(OPT_NOT_MATCH), filename); + goto err; + } // endif + + if (fread(n, sizeof(int), 2, opfile) != 2) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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. + snprintf(g->Message, sizeof(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())) { + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(g->Message), MSG(INDX_COL_NOTIN), kdp->GetName(), Name); + goto err; + } else if (colp->GetResultType() == TYPE_DECIM) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(g->Message), "Wrong column %s", kdp->GetName()); + return true; + } else + To_Key_Col[k++] = colp; + +#if defined(_DEBUG) + if (k != Knum) { + snprintf(g->Message, sizeof(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. */ + /*******************************************************************/ + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(g->Message), MSG(BAD_RECFM), tdbp->Ftype); + throw 34; + } // endswitch Ftype + + if (err) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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); + + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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]; + + snprintf(g->Message, sizeof(g->Message), MSG(DVAL_NOTIN_LIST), + Value->GetCharString(buf), Name); + return true; + } else if (i >= dup->Maxbmp) { + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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..dcd93539 --- /dev/null +++ b/storage/connect/tabext.cpp @@ -0,0 +1,800 @@ +/************* 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); + + // Memory was Boolean, it is now integer + if (!(Memory = GetIntCatInfo("Memory", 0))) + Memory = GetBoolCatInfo("Memory", false) ? 1 : 0; + + if ((Srcdef = GetStringCatInfo(g, "Srcdef", NULL))) { + Read_Only = true; + if (Memory == 2) Memory = 1; + } // endif Srcdef + + 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); + Qchar = GetStringCatInfo(g,"Qchar", NULL); + if (Qchar && !Quoted) + Quoted = 1; + 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); + + 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()); + Quote = tdp->GetQchar(); + 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; + Quote = NULL; + Rows = 0; + Memory = 0; + Scrollable = false; + } // endif tdp + + 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; + Quote = tdbp->Quote; + 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 + +/* + Count number of %s placeholders in string. + Returns -1 if other sprintf placeholders are found, .g %d +*/ +static int count_placeholders(const char *fmt) +{ + int cnt= 0; + for (const char *p=fmt; *p; p++) + { + if (*p == '%') + { + switch (p[1]) + { + case 's': + /* %s found */ + cnt++; + p++; + break; + case '%': + /* masking char for % found */ + p++; + break; + default: + /* some other placeholder found */ + return -1; + } + } + } + return cnt; +} + +/***********************************************************************/ +/* 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 + + int n_placeholders = count_placeholders(Srcdef); + if (n_placeholders < 0) + { + strcpy(g->Message, "MakeSQL: Wrong place holders specification"); + return true; + } + + if (!stricmp(ph, "W") && n_placeholders <= 1) { + Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1)); + Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil1)); + } + else if (!stricmp(ph, "WH") && n_placeholders <= 2) + { + Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1) + strlen(fil2)); + Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil1, fil2)); + } + else if (!stricmp(ph, "H") && n_placeholders <= 1) + { + Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil2)); + Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil2)); + } + else if (!stricmp(ph, "HW") && n_placeholders <= 2) + { + 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; + char *res= NULL, *my_schema_table= NULL; + size_t my_len= 0; + + 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) { + // Tabname can have both database and table identifiers, we need to parse + if (res= strstr(buf, ".")) + { + // Parse schema + my_len= res - buf + 1; + my_schema_table= (char *) malloc(my_len); + memcpy(my_schema_table, buf, my_len - 1); + my_schema_table[my_len] = 0; + Query->Append(Quote); + Query->Append(my_schema_table); + Query->Append(Quote); + free(my_schema_table); + Query->Append("."); + // Parse table + my_len= strlen(buf) - my_len + 1; + my_schema_table= (char *) malloc(my_len); + memcpy(my_schema_table, ++res, my_len); + my_schema_table[my_len] = 0; + Query->Append(Quote); + Query->Append(my_schema_table); + Query->Append(Quote); + free(my_schema_table); + } + else + { + // 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 { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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..8a0d6c78 --- /dev/null +++ b/storage/connect/tabext.h @@ -0,0 +1,205 @@ +/*************** 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 PSZ GetQchar(void) { return Qchar; } + 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..c965b638 --- /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 +#include +#include +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif // __BORLANDC__ +//#include +#else // !_WIN32 +#if defined(UNIX) +#include +#include +#include +#include +#else // !UNIX +#include +#endif // !UNIX +#include +#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. */ + /*****************************************************************/ + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(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(p); + else + Value->SetBinValue(p); + + break; + case 'S': // Short integer + Value->SetValueNonAligned(p); + break; + case 'T': // Tiny integer + Value->SetValue(*p); + break; + case 'I': // Integer + Value->SetValueNonAligned(p); + break; + case 'G': // Large (great) integer + Value->SetValueNonAligned(p); + break; + case 'F': // Float + case 'R': // Real + Value->SetValueNonAligned(p); + break; + case 'D': // Double + Value->SetValueNonAligned(p); + break; + case 'C': // Text + if (Value->SetValue_char(p, Long)) { + snprintf(g->Message, sizeof(g->Message), "Out of range value for column %s at row %d", + Name, tdbp->RowNumber(g)); + PushWarning(g, tdbp); + } // endif SetValue_char + + break; + default: + snprintf(g->Message, sizeof(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(p, Value->GetBigintValue()); + } else if (Value->GetBinValue(p, Long, Status)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), MSG(VALUE_TOO_BIG), n, Name); + throw 31; + } else if (Status) + Value->GetValueNonAligned(p, (short)n); + + break; + case 'T': // Tiny integer + n = Value->GetBigintValue(); + + if (n > 255LL || n < -256LL) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), MSG(VALUE_TOO_BIG), n, Name); + throw 31; + } else if (Status) + Value->GetValueNonAligned(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(p, (float)Value->GetFloatValue()); + + break; + case 'D': // Double + if (Status) + Value->GetValueNonAligned(p, Value->GetFloatValue()); + + break; + case 'C': // Characters + if ((n = (signed)strlen(Value->GetCharString(Buf))) > Long) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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..e742ed22 --- /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 +#include +#include +#include +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif +//#include +#include "osutil.h" +#else +#if defined(UNIX) +#include +#include +#include "osutil.h" +#else +#include +#endif +#include +#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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), MSG(EOF_AFTER_LINE), num_read -1); + break; + } else { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { +// snprintf(g->Message, sizeof(g->Message), MSG(QUOTE_IN_QUOTE), num_read); +// goto err; +// } else +// goto skip; + + p++; + n++; + } else + phase = 2; + + } else if (++nerr > mxr) { // phase == 2 + snprintf(g->Message, sizeof(g->Message), MSG(MISPLACED_QUOTE), num_read); + goto err; + } else + goto skip; + + } else { + if (phase == 2) { + if (++nerr > mxr) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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()) { + snprintf(g->Message, sizeof(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()) { + snprintf(g->Message, sizeof(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()) { + snprintf(g->Message, sizeof(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]) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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())) { + snprintf(g->Message, sizeof(g->Message), MSG(NO_FLD_FORMAT), i + 1, Name); + return true; + } // endif pfm + + // Roughly check the Fmt format + if ((n = strlen(pfm) - 2) < 4) { + snprintf(g->Message, sizeof(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()) { + snprintf(g->Message, sizeof(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]) { +// snprintf(g->Message, sizeof(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) + { + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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..c46b5a30 --- /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) + {snprintf(g->Message, sizeof(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..46fb7695 --- /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 +#include +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif +//#include +#include +#else +#if defined(UNIX) +#include +#define NODW +#include "osutil.h" +#else +#include +#endif +#include +#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))) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), "Missing URL for JDBC table %s", Name); + return true; + } // endif Url + + } // endif Connect + + if (Url) + if ((rc = ParseURL(g, Url)) == RC_FX) { + snprintf(g->Message, sizeof(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); + + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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; + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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..06a91f57 --- /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 + +/***********************************************************************/ +/* 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])) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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..968253ec --- /dev/null +++ b/storage/connect/tabjson.cpp @@ -0,0 +1,2706 @@ +/************* 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 +#include +#include + +/***********************************************************************/ +/* 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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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] != ']') { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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] != ']') { + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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 { + snprintf(g->Message, sizeof(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 + + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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: // ?????????? + snprintf(g->Message, sizeof(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())) { + snprintf(g->Message, sizeof(g->Message), "Cannot find object key %s", key); + return RC_FX; + } // endif val + + } else { + if (*p == '[') { + // Old style + if (p[strlen(p) - 1] != ']') { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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..b0b5b86c --- /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)) { + snprintf(g->Message, sizeof(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 { + snprintf(g->Message, sizeof(g->Message), MSG(BAD_SPECIAL_COL), name); + return NULL; + } // endif's name + + if (!(colp = InsertSpecialColumn(colp))) { + snprintf(g->Message, sizeof(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) + { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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 { + snprintf(g->Message, sizeof(g->Message), MSG(BAD_SPECIAL_COL), name); + return NULL; + } // endif's name + + if (!(colp = InsertSpecialColumn(colp))) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), "Result limited to %d lines", Qrp->Maxres); + PushWarning(g, this); + } // endif Truncated + + if (Qrp->BadLines) { + snprintf(g->Message, sizeof(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()*/) { + snprintf(g->Message, sizeof(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..723dc359 --- /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 +#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) + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 +#include +#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..4fad2b27 --- /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 +#include +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif +//#include +#if defined(PATHMATCHSPEC) +#include "Shlwapi.h" +//using namespace std; +#pragma comment(lib,"shlwapi.lib") +#endif // PATHMATCHSPEC +#else +#if defined(UNIX) +#include +#include +#include +#include +#include +#include "osutil.h" +#else +//#include +#endif +//#include +#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); + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 +#else // !_WIN32 +#include +#include +#include +#include +#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..7192b572 --- /dev/null +++ b/storage/connect/tabmysql.cpp @@ -0,0 +1,1755 @@ +/************* 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 +#else // !_WIN32 +//#include +//#include +#include +#include +#include +#include "osutil.h" +//#include +//#include +#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; + Ignored = 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"; + + Delayed = !!GetIntCatInfo("Delayed", 0); + Ignored = !!GetIntCatInfo("Ignored", 0); + + 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); + } 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; + Ignored = tdp->Ignored; + 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; + Ignored = 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; + Ignored = tdbp->Ignored; + 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); + + Query->Set("INSERT "); + if (Delayed) + Query->Append("DELAYED "); + if (Ignored) + Query->Append("IGNORE "); + + Query->Append("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 { + snprintf(g->Message, sizeof(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); + if (Mode == MODE_READ && !Query) + { + Myc.Close(); + return true; + } + m_Rc = (Mode == MODE_READ) + ? Myc.ExecSQL(g, Query->GetStr()) : RC_OK; + +#if 0 + if (!Myc.m_Res || !Myc.m_Fields) { + snprintf(g->Message, sizeof(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 + + } 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) + snprintf(g->Message, sizeof(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; + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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()) { + + 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 + + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(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..b5af77de --- /dev/null +++ b/storage/connect/tabmysql.h @@ -0,0 +1,254 @@ +// 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 Ignored; /* Use insert IGNORE */ +//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 + bool Ignored; // Use insert IGNORE + 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..fabbf655 --- /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 +#include +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif +//#include +#else +#if defined(UNIX) +#include +#include +#include +#include +#include +#include "osutil.h" +#else +//#include +#endif +//#include +#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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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..d60cd039 --- /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 +#include +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif +//#include +#include +#else +#if defined(UNIX) +#include +#define NODW +#include "osutil.h" +#else +#include +#endif +#include +#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) { + snprintf(g->Message, sizeof(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 (Query && (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); + + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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())) { + snprintf(g->Message, sizeof(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())) { + snprintf(g->Message, sizeof(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..ba9b9033 --- /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 +#elif defined(UNIX) +#include +#include +#include "osutil.h" +#else +#include +#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) { + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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. */ + /*******************************************************************/ + snprintf(g->Message, sizeof(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) + { + snprintf(g->Message, sizeof(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) + { + snprintf(g->Message, sizeof(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..c535c21f --- /dev/null +++ b/storage/connect/tabrest.cpp @@ -0,0 +1,363 @@ +/************** 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 // All MariaDB stuff +#include +#include +#if !defined(_WIN32) && !defined(_WINDOWS) +#include +#include +#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 { + snprintf(g->Message, sizeof(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 + +#ifdef HAVE_VFORK + pID = vfork(); +#else + pID = fork(); +#endif + 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(); + + snprintf(g->Message, sizeof(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(); + + snprintf(g->Message, sizeof(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(); + snprintf(g->Message, sizeof(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(); + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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..901d9102 --- /dev/null +++ b/storage/connect/tabrest.h @@ -0,0 +1,48 @@ +/*************** 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) +#else // !_WIN32 +#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..7d90b467 --- /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 +#else // !_WIN32 +#if defined(UNIX) +#include +#include +#else // !UNIX +#include +#endif // !UNIX +#include +#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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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..b2240bff --- /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 +#include +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif +//#include +#else +#if defined(UNIX) +#include +#include +#include +#include +#include +#include "osutil.h" +#else +//#include +#endif +//#include +#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))) { + snprintf(g->Message, sizeof(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..02908927 --- /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 +#include "sql_class.h" +#include "table.h" +#include "field.h" +#if defined(_WIN32) +#include +#include +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif +//#include +#else +#if defined(UNIX) +#include +#include +#include +#include +#include +#include "osutil.h" +#else +//#include +#endif +//#include +#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 + + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(g->Message), "Column %s skipped (unsupported type)", colname); + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message); + continue; + } // endif v + + snprintf(g->Message, sizeof(g->Message), "Column %s unsupported type", colname); + qrp = NULL; + break; + } // endif type + + if (v == 'X') { + len = zconv; + snprintf(g->Message, sizeof(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()->coll_name.str; + 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)) { + snprintf(g->Message, sizeof(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, sizeof(g->Message), "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))) { + snprintf(g->Message, sizeof(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 { + snprintf(g->Message, sizeof(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 +#include +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif +//#include +#include +#else +#if defined(UNIX) +#include +#include +#include +#include +#define NO_ERROR 0 +#else +#include +#endif +#include +#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 +#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..0c4a41be --- /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 + +/***********************************************************************/ +/* 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) + { + snprintf(g->Message, sizeof(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) + { + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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..935d21c5 --- /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 + +#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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(g->Message), "failed Get(__Property_Count) res=%d\n", res); + goto err; + } // endif res + + if (!(n = val.lVal)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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); + + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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((long long)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); + + snprintf(buf, sizeof(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 +# pragma comment(lib, "wbemuuid.lib") +#include +using namespace std; +#include + +/***********************************************************************/ +/* 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 +#include +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif +//#include +#else +#if defined(UNIX) +#include +#include +#include +#include +#include +#include "osutil.h" +#else +//#include +#endif +//#include +#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..a5957178 --- /dev/null +++ b/storage/connect/tabxml.cpp @@ -0,0 +1,2300 @@ +/************* 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 +#include +#if defined(_WIN32) +#include +#include +//#include +#include +#else // !_WIN32 +#include +#include +#include +#include +//#include +#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; + size_t xlen= strlen(xcol->Name); + strmake(colname, vp->atp->GetName(g), z); + strmake(xcol->Name + xlen, colname, + sizeof(xcol->Name) - 1 - xlen); + + 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 { + size_t xlen; + if (tdp->Usedom && node->GetType() != 1) + continue; + + xlen= strlen(xcol->Name); + strmake(colname, node->GetName(g), sizeof(colname)-1); + strmake(xcol->Name + xlen, colname, sizeof(xcol->Name) - 1 - xlen); + + 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: + snprintf(g->Message, sizeof(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() : "", 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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(g->Message), MSG(MISSING_NODE), XmlDB, Xfile); + goto error; + } // endif DBnode + + if (!(TabNode = DBnode->AddChildNode(g, Tabname))) { + snprintf(g->Message, sizeof(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 { + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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) + snprintf(g->Message, sizeof(g->Message), "%s: %s", MSG(COM_ERROR), buf); + else + snprintf(g->Message, sizeof(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. */ + /*******************************************************************/ + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + char *p = strstr(Tdbp->Colname, "%d"); + if (p) + snprintf(pbuf, len + 3, "%.*s%d%s/", (int) (p - Tdbp->Colname), Tdbp->Colname, + Rank + (Tdbp->Usedom ? 0 : 1), p + 2); + else + snprintf(pbuf, len + 3, "%s/", Tdbp->Colname); + } // endif Colname + + if (Xname) { + if (Type == 2) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(g->Message), MSG(XPATH_NOT_SUPP), Name); + return true; + } else + Nodes[i] = p; + + *p2 = '\0'; + } // endif mode + + } // endfor i, p + + if (*p == '/' || *p == '.') { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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; + + // refresh CList in case its Listp was freed in SelectSingleNode above + if (Tdbp->Clist) + Tdbp->RowNode->SelectNodes(g, Tdbp->Colname, Tdbp->Clist); + } // 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) { + snprintf(g->Message, sizeof(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; + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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..3f41bf9f --- /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 + +/***********************************************************************/ +/* 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))) + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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 +#include +#include + +#ifndef NOUNCRYPT + #define NOUNCRYPT +#endif + +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#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 (c1c2) + 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 (uBackReaduMaxBack) + 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 (uBackReaduMaxBack) + 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_pospfile_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_filename0) && (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_extraz_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_commentz_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_compressedrest_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;iread_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;istream.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 +#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..528c4abf --- /dev/null +++ b/storage/connect/valblk.cpp @@ -0,0 +1,1416 @@ +/************ 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 +#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(mp, nval, type, 0, true); + else + blkp = new(g) TYPBLK(mp, nval, type); + + break; + case TYPE_INT: + if (un) + blkp = new(g) TYPBLK(mp, nval, type, 0, true); + else + blkp = new(g) TYPBLK(mp, nval, type); + + break; + case TYPE_DATE: // ????? + blkp = new(g) DATBLK(mp, nval); + break; + case TYPE_BIGINT: + if (un) + blkp = new(g) TYPBLK(mp, nval, type, 0, true); + else + blkp = new(g) TYPBLK(mp, nval, type); + + break; + case TYPE_DOUBLE: + blkp = new(g) TYPBLK(mp, nval, type, prec); + break; + case TYPE_TINY: + if (un) + blkp = new(g) TYPBLK(mp, nval, type, 0, true); + else + blkp = new(g) TYPBLK(mp, nval, type); + + break; + case TYPE_PCHAR: + blkp = new(g) PTRBLK(g, mp, nval); + break; + default: + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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) + { + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(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 +TYPBLK::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 +bool TYPBLK::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 +char *TYPBLK::GetCharString(char *p, int n) + { + sprintf(p, Fmt, UnalignedRead(n)); + return p; + } // end of GetCharString + +template <> +char *TYPBLK::GetCharString(char *p, int n) + { + sprintf(p, Fmt, Prec, UnalignedRead(n)); + return p; + } // end of GetCharString + +/***********************************************************************/ +/* Set one value in a block. */ +/***********************************************************************/ +template +void TYPBLK::SetValue(PVAL valp, int n) + { + bool b; + + ChkIndx(n); + ChkTyp(valp); + + if (!(b = valp->IsNull())) + UnalignedWrite(n, GetTypedValue(valp)); + else + Reset(n); + + SetNull(n, b && Nullable); + } // end of SetValue + +template <> +int TYPBLK::GetTypedValue(PVAL valp) + {return valp->GetIntValue();} + +template <> +uint TYPBLK::GetTypedValue(PVAL valp) + {return valp->GetUIntValue();} + +template <> +short TYPBLK::GetTypedValue(PVAL valp) + {return valp->GetShortValue();} + +template <> +ushort TYPBLK::GetTypedValue(PVAL valp) + {return valp->GetUShortValue();} + +template <> +longlong TYPBLK::GetTypedValue(PVAL valp) + {return valp->GetBigintValue();} + +template <> +ulonglong TYPBLK::GetTypedValue(PVAL valp) + {return valp->GetUBigintValue();} + +template <> +double TYPBLK::GetTypedValue(PVAL valp) + {return valp->GetFloatValue();} + +template <> +char TYPBLK::GetTypedValue(PVAL valp) + {return valp->GetTinyValue();} + +template <> +uchar TYPBLK::GetTypedValue(PVAL valp) + {return valp->GetUTinyValue();} + +/***********************************************************************/ +/* Set one value in a block from a zero terminated string. */ +/***********************************************************************/ +template +void TYPBLK::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) + UnalignedWrite(n, (TYPE)(-(signed)val)); + else + UnalignedWrite(n, (TYPE)val); + + SetNull(n, false); + } // end of SetValue + +template +ulonglong TYPBLK::MaxVal(void) {DBUG_ASSERT(false); return 0;} + +template <> +ulonglong TYPBLK::MaxVal(void) {return INT_MAX16;} + +template <> +ulonglong TYPBLK::MaxVal(void) {return UINT_MAX16;} + +template <> +ulonglong TYPBLK::MaxVal(void) {return INT_MAX32;} + +template <> +ulonglong TYPBLK::MaxVal(void) {return UINT_MAX32;} + +template <> +ulonglong TYPBLK::MaxVal(void) {return INT_MAX8;} + +template <> +ulonglong TYPBLK::MaxVal(void) {return UINT_MAX8;} + +template <> +ulonglong TYPBLK::MaxVal(void) {return INT_MAX64;} + +template <> +ulonglong TYPBLK::MaxVal(void) {return ULONGLONG_MAX;} + +template <> +void TYPBLK::SetValue(PCSZ p, int n) + { + ChkIndx(n); + + if (Check) { + PGLOBAL& g = Global; + strcpy(g->Message, MSG(BAD_SET_STRING)); + throw Type; + } // endif Check + + UnalignedWrite(n, atof(p)); + SetNull(n, false); + } // end of SetValue + +/***********************************************************************/ +/* Set one value in a block from an array of characters. */ +/***********************************************************************/ +template +void TYPBLK::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 +void TYPBLK::SetValue(PVBLK pv, int n1, int n2) + { + bool b; + + ChkIndx(n1); + ChkTyp(pv); + + if (!(b = pv->IsNull(n2) && Nullable)) + UnalignedWrite(n1, GetTypedValue(pv, n2)); + else + Reset(n1); + + SetNull(n1, b); + } // end of SetValue + +template <> +int TYPBLK::GetTypedValue(PVBLK blk, int n) + {return blk->GetIntValue(n);} + +template <> +uint TYPBLK::GetTypedValue(PVBLK blk, int n) + {return blk->GetUIntValue(n);} + +template <> +short TYPBLK::GetTypedValue(PVBLK blk, int n) + {return blk->GetShortValue(n);} + +template <> +ushort TYPBLK::GetTypedValue(PVBLK blk, int n) + {return blk->GetUShortValue(n);} + +template <> +longlong TYPBLK::GetTypedValue(PVBLK blk, int n) + {return blk->GetBigintValue(n);} + +template <> +ulonglong TYPBLK::GetTypedValue(PVBLK blk, int n) + {return blk->GetUBigintValue(n);} + +template <> +double TYPBLK::GetTypedValue(PVBLK blk, int n) + {return blk->GetFloatValue(n);} + +template <> +char TYPBLK::GetTypedValue(PVBLK blk, int n) + {return blk->GetTinyValue(n);} + +template <> +uchar TYPBLK::GetTypedValue(PVBLK blk, int n) + {return blk->GetUTinyValue(n);} + +/***********************************************************************/ +/* Set one value in a block if val is less than the current value. */ +/***********************************************************************/ +template +void TYPBLK::SetMin(PVAL valp, int n) + { + CheckParms(valp, n) + TYPE tval = GetTypedValue(valp); + TYPE tmin = UnalignedRead(n); + + if (tval < tmin) + UnalignedWrite(n, tval); + + } // end of SetMin + +/***********************************************************************/ +/* Set one value in a block if val is greater than the current value. */ +/***********************************************************************/ +template +void TYPBLK::SetMax(PVAL valp, int n) + { + CheckParms(valp, n) + TYPE tval = GetTypedValue(valp); + TYPE tmin = UnalignedRead(n); + + if (tval > tmin) + UnalignedWrite(n, tval); + + } // end of SetMax + +#if 0 +/***********************************************************************/ +/* Set many values in a block from values in another block. */ +/***********************************************************************/ +template +void TYPBLK::SetValues(PVBLK pv, int k, int n) + { + CheckType(pv) + TYPE *lp = ((TYPBLK*)pv)->Typp; + + memcpy(Typp + k, lp + k, sizeof(TYPE) * n); + + } // end of SetValues +#endif // 0 + +/***********************************************************************/ +/* Move one value from i to j. */ +/***********************************************************************/ +template +void TYPBLK::Move(int i, int j) + { + UnalignedWrite(j, UnalignedRead(i)); + MoveNull(i, j); + } // end of Move + +/***********************************************************************/ +/* Compare a Value object with the nth value of the block. */ +/***********************************************************************/ +template +int TYPBLK::CompVal(PVAL vp, int n) + { +#if defined(_DEBUG) + ChkIndx(n); + ChkTyp(vp); +#endif // _DEBUG + TYPE mlv = UnalignedRead(n); + TYPE vlv = GetTypedValue(vp); + + return (vlv > mlv) ? 1 : (vlv < mlv) ? (-1) : 0; + } // end of CompVal + +/***********************************************************************/ +/* Compare two values of the block. */ +/***********************************************************************/ +template +int TYPBLK::CompVal(int i1, int i2) + { + TYPE lv1 = UnalignedRead(i1); + TYPE lv2 = UnalignedRead(i2); + + return (lv1 > lv2) ? 1 : (lv1 < lv2) ? (-1) : 0; + } // end of CompVal + +/***********************************************************************/ +/* Get a pointer on the nth value of the block. */ +/***********************************************************************/ +template +void *TYPBLK::GetValPtr(int n) + { + ChkIndx(n); + return Typp + n; + } // end of GetValPtr + +/***********************************************************************/ +/* Get a pointer on the nth value of the block. */ +/***********************************************************************/ +template +void *TYPBLK::GetValPtrEx(int n) + { + ChkIndx(n); + return Typp + n; + } // end of GetValPtrEx + +/***********************************************************************/ +/* Returns index of matching value in block or -1. */ +/***********************************************************************/ +template +int TYPBLK::Find(PVAL vp) + { + ChkTyp(vp); + + int i; + TYPE n = GetTypedValue(vp); + + for (i = 0; i < Nval; i++) + if (n == UnalignedRead(i)) + break; + + return (i < Nval) ? i : (-1); + } // end of Find + +/***********************************************************************/ +/* Returns the length of the longest string in the block. */ +/***********************************************************************/ +template +int TYPBLK::GetMaxLength(void) + { + char buf[64]; + int i, n, m; + + for (i = n = 0; i < Nval; i++) { + m = snprintf(buf, sizeof(buf), Fmt, UnalignedRead(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(""); + + 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(""); + } // 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(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(UnalignedRead(n)); + vp = Dvalp->GetCharString(p); + } else + vp = TYPBLK::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); + UnalignedWrite(n, Dvalp->GetIntValue()); + } else + TYPBLK::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)) { + snprintf(g->Message, sizeof(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())) { + snprintf(g->Message, sizeof(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..537e838c --- /dev/null +++ b/storage/connect/valblk.h @@ -0,0 +1,375 @@ +/*************** 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 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)UnalignedRead(n);} + virtual uchar GetUTinyValue(int n) {return (uchar)UnalignedRead(n);} + virtual short GetShortValue(int n) {return (short)UnalignedRead(n);} + virtual ushort GetUShortValue(int n) {return (ushort)UnalignedRead(n);} + virtual int GetIntValue(int n) {return (int)UnalignedRead(n);} + virtual uint GetUIntValue(int n) {return (uint)UnalignedRead(n);} + virtual longlong GetBigintValue(int n) {return (longlong)UnalignedRead(n);} + virtual ulonglong GetUBigintValue(int n) {return (ulonglong)UnalignedRead(n);} + virtual double GetFloatValue(int n) {return (double)UnalignedRead(n);} + virtual char *GetCharString(char *p, int n); + virtual void Reset(int n) {UnalignedWrite(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) + {UnalignedWrite(n, (TYPE)sval); SetNull(n, false);} + virtual void SetValue(ushort sval, int n) + {UnalignedWrite(n, (TYPE)sval); SetNull(n, false);} + virtual void SetValue(int lval, int n) + {UnalignedWrite(n, (TYPE)lval); SetNull(n, false);} + virtual void SetValue(uint lval, int n) + {UnalignedWrite(n, (TYPE)lval); SetNull(n, false);} + virtual void SetValue(longlong lval, int n) + {UnalignedWrite(n, (TYPE)lval); SetNull(n, false);} + virtual void SetValue(ulonglong lval, int n) + {UnalignedWrite(n, (TYPE)lval); SetNull(n, false);} + virtual void SetValue(double fval, int n) + {UnalignedWrite(n, (TYPE)fval); SetNull(n, false);} + virtual void SetValue(char cval, int n) + {UnalignedWrite(n, (TYPE)cval); SetNull(n, false);} + virtual void SetValue(uchar cval, int n) + {UnalignedWrite(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; + + // Unaligned access + TYPE UnalignedRead(int n) const { + TYPE result; + memcpy(&result, Typp + n, sizeof(TYPE)); + return result; + } + + void UnalignedWrite(int n, TYPE value) { + memcpy(Typp + n, &value, sizeof(TYPE)); + } + }; // 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 { + 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::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..9586f834 --- /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 +#else // !_WIN32 +#include +#endif // !_WIN32 + +#include + +#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)value, prec); + break; + case TYPE_SHORT: + valp = new(g) TYPVAL(*(short*)value, TYPE_SHORT); + break; + case TYPE_INT: + valp = new(g) TYPVAL(*(int*)value, TYPE_INT); + break; + case TYPE_BIGINT: + valp = new(g) TYPVAL(*(longlong*)value, TYPE_BIGINT); + break; + case TYPE_DOUBLE: + valp = new(g) TYPVAL(*(double *)value, TYPE_DOUBLE, prec); + break; + case TYPE_TINY: + valp = new(g) TYPVAL(*(char *)value, TYPE_TINY); + break; + default: + snprintf(g->Message, sizeof(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(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)0, TYPE_INT, 0, true); + else + valp = new(g) TYPVAL((int)0, TYPE_INT); + + break; + case TYPE_BIGINT: + if (uns) + valp = new(g) TYPVAL((ulonglong)0, TYPE_BIGINT, 0, true); + else + valp = new(g) TYPVAL((longlong)0, TYPE_BIGINT); + + break; + case TYPE_SHORT: + if (uns) + valp = new(g) TYPVAL((ushort)0, TYPE_SHORT, 0, true); + else + valp = new(g) TYPVAL((short)0, TYPE_SHORT); + + break; + case TYPE_DOUBLE: + valp = new(g) TYPVAL(0.0, TYPE_DOUBLE, prec); + break; + case TYPE_TINY: + if (uns) + valp = new(g) TYPVAL((uchar)0, TYPE_TINY, 0, true); + else + valp = new(g) TYPVAL((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: + snprintf(g->Message, sizeof(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(g, p, valp->GetValLen(), valp->GetValPrec()); + break; + case TYPE_SHORT: + if (un) + vp = new(g) TYPVAL(valp->GetUShortValue(), + TYPE_SHORT, 0, true); + else + vp = new(g) TYPVAL(valp->GetShortValue(), TYPE_SHORT); + + break; + case TYPE_INT: + if (un) + vp = new(g) TYPVAL(valp->GetUIntValue(), TYPE_INT, 0, true); + else + vp = new(g) TYPVAL(valp->GetIntValue(), TYPE_INT); + + break; + case TYPE_BIGINT: + if (un) + vp = new(g) TYPVAL(valp->GetUBigintValue(), + TYPE_BIGINT, 0, true); + else + vp = new(g) TYPVAL(valp->GetBigintValue(), TYPE_BIGINT); + + break; + case TYPE_DATE: + vp = new(g) DTVAL(valp->GetIntValue()); + break; + case TYPE_DOUBLE: + vp = new(g) TYPVAL(valp->GetFloatValue(), TYPE_DOUBLE, + (uns) ? uns : valp->GetValPrec()); + break; + case TYPE_TINY: + if (un) + vp = new(g) TYPVAL(valp->GetUTinyValue(), + TYPE_TINY, 0, true); + else + vp = new(g) TYPVAL(valp->GetTinyValue(), TYPE_TINY); + + break; + default: + snprintf(g->Message, sizeof(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\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, ""); + else + p = GetCharString(buf); + + strncpy(ps, p, z); +} // end of Prints + +/* -------------------------- Class TYPVAL ---------------------------- */ + +/***********************************************************************/ +/* TYPVAL public constructor from a constant typed value. */ +/***********************************************************************/ +template +TYPVAL::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 +ulonglong TYPVAL::MaxVal(void) {DBUG_ASSERT(false); return 0;} + +template <> +ulonglong TYPVAL::MaxVal(void) {return INT_MAX16;} + +template <> +ulonglong TYPVAL::MaxVal(void) {return UINT_MAX16;} + +template <> +ulonglong TYPVAL::MaxVal(void) {return INT_MAX32;} + +template <> +ulonglong TYPVAL::MaxVal(void) {return UINT_MAX32;} + +template <> +ulonglong TYPVAL::MaxVal(void) {return INT_MAX8;} + +template <> +ulonglong TYPVAL::MaxVal(void) {return UINT_MAX8;} + +template <> +ulonglong TYPVAL::MaxVal(void) {return INT_MAX64;} + +template <> +ulonglong TYPVAL::MaxVal(void) {return ULONGLONG_MAX;} + +/***********************************************************************/ +/* TYPVAL GetValLen: returns the print length of the typed object. */ +/***********************************************************************/ +template +int TYPVAL::GetValLen(void) +{ + char c[32]; + + return snprintf(c, 32, Fmt, Tval); +} // end of GetValLen + +template <> +int TYPVAL::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 +bool TYPVAL::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::GetTypedValue(PVAL valp) + {return valp->GetShortValue();} + +template <> +ushort TYPVAL::GetTypedValue(PVAL valp) + {return valp->GetUShortValue();} + +template <> +int TYPVAL::GetTypedValue(PVAL valp) + {return valp->GetIntValue();} + +template <> +uint TYPVAL::GetTypedValue(PVAL valp) + {return valp->GetUIntValue();} + +template <> +longlong TYPVAL::GetTypedValue(PVAL valp) + {return valp->GetBigintValue();} + +template <> +ulonglong TYPVAL::GetTypedValue(PVAL valp) + {return valp->GetUBigintValue();} + +template <> +double TYPVAL::GetTypedValue(PVAL valp) + {return valp->GetFloatValue();} + +template <> +char TYPVAL::GetTypedValue(PVAL valp) + {return valp->GetTinyValue();} + +template <> +uchar TYPVAL::GetTypedValue(PVAL valp) + {return valp->GetUTinyValue();} + +/***********************************************************************/ +/* TYPVAL SetValue: convert chars extracted from a line to TYPE value.*/ +/***********************************************************************/ +template +bool TYPVAL::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::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 +void TYPVAL::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 +void TYPVAL::SetValue_pvblk(PVBLK blk, int n) +{ + Tval = GetTypedValue(blk, n); + Null = false; +} // end of SetValue + +template <> +int TYPVAL::GetTypedValue(PVBLK blk, int n) + {return blk->GetIntValue(n);} + +template <> +uint TYPVAL::GetTypedValue(PVBLK blk, int n) + {return blk->GetUIntValue(n);} + +template <> +short TYPVAL::GetTypedValue(PVBLK blk, int n) + {return blk->GetShortValue(n);} + +template <> +ushort TYPVAL::GetTypedValue(PVBLK blk, int n) + {return blk->GetUShortValue(n);} + +template <> +longlong TYPVAL::GetTypedValue(PVBLK blk, int n) + {return blk->GetBigintValue(n);} + +template <> +ulonglong TYPVAL::GetTypedValue(PVBLK blk, int n) + {return blk->GetUBigintValue(n);} + +template <> +double TYPVAL::GetTypedValue(PVBLK blk, int n) + {return blk->GetFloatValue(n);} + +template <> +char TYPVAL::GetTypedValue(PVBLK blk, int n) + {return blk->GetTinyValue(n);} + +template <> +uchar TYPVAL::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 +void TYPVAL::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 + 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 +bool TYPVAL::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 + memcpy(buf, &Tval, sizeof(TYPE)); +#endif + + Null = false; + return false; +} // end of GetBinValue + +/***********************************************************************/ +/* TYPVAL ShowValue: get string representation of a typed value. */ +/***********************************************************************/ +template +int TYPVAL::ShowValue(char *buf, int len) +{ + return snprintf(buf, len + 1, Xfmt, len, Tval); +} // end of ShowValue + +template <> +int TYPVAL::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 +char *TYPVAL::GetCharString(char *p) +{ + sprintf(p, Fmt, Tval); + return p; +} // end of GetCharString + +template <> +char *TYPVAL::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 +char *TYPVAL::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 +char *TYPVAL::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 +char *TYPVAL::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 +char *TYPVAL::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 +char *TYPVAL::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 +bool TYPVAL::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 +int TYPVAL::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::MinMaxVal(bool b) + {return (b) ? INT_MAX16 : INT_MIN16;} + +template <> +ushort TYPVAL::MinMaxVal(bool b) + {return (b) ? UINT_MAX16 : 0;} + +template <> +int TYPVAL::MinMaxVal(bool b) + {return (b) ? INT_MAX32 : INT_MIN32;} + +template <> +uint TYPVAL::MinMaxVal(bool b) + {return (b) ? UINT_MAX32 : 0;} + +template <> +longlong TYPVAL::MinMaxVal(bool b) + {return (b) ? INT_MAX64 : INT_MIN64;} + +template <> +ulonglong TYPVAL::MinMaxVal(bool b) + {return (b) ? 0xFFFFFFFFFFFFFFFFLL : 0;} + +template <> +double TYPVAL::MinMaxVal(bool) + {assert(false); return 0.0;} + +template <> +char TYPVAL::MinMaxVal(bool b) + {return (b) ? INT_MAX8 : INT_MIN8;} + +template <> +uchar TYPVAL::MinMaxVal(bool b) + {return (b) ? UINT_MAX8 : 0;} + +/***********************************************************************/ +/* SafeAdd: adds a value and test whether overflow/underflow occurred. */ +/***********************************************************************/ +template +TYPE TYPVAL::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::SafeAdd(double n1, double n2) +{ + return n1 + n2; +} // end of SafeAdd + +/***********************************************************************/ +/* SafeMult: multiply values and test whether overflow occurred. */ +/***********************************************************************/ +template +TYPE TYPVAL::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::SafeMult(double n1, double n2) +{ + return n1 * n2; +} // end of SafeMult + +/***********************************************************************/ +/* Compute defined functions for the type. */ +/***********************************************************************/ +template +bool TYPVAL::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::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 +bool TYPVAL::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: +// snprintf(g->Message, sizeof(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 +bool TYPVAL::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 +bool TYPVAL::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::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::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::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::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::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::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::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::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::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::GetUBigintValue(void) +{ + return CharToNumber(Strp, strlen(Strp), ULONGLONG_MAX, true); +} // end of GetUBigintValue + +/***********************************************************************/ +/* STRING SetValue: copy the value of another Value object. */ +/***********************************************************************/ +bool TYPVAL::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::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::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::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::SetValue(int n) +{ + char buf[16]; + PGLOBAL& g = Global; + int k = sprintf(buf, "%d", n); + + if (k > Len) { + snprintf(g->Message, sizeof(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::SetValue(uint n) +{ + char buf[16]; + PGLOBAL& g = Global; + int k = sprintf(buf, "%u", n); + + if (k > Len) { + snprintf(g->Message, sizeof(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::SetValue(short i) +{ + SetValue((int)i); + Null = false; +} // end of SetValue + +/***********************************************************************/ +/* STRING SetValue: get the character representation of a ushort int. */ +/***********************************************************************/ +void TYPVAL::SetValue(ushort i) +{ + SetValue((uint)i); + Null = false; +} // end of SetValue + +/***********************************************************************/ +/* STRING SetValue: get the character representation of a big integer.*/ +/***********************************************************************/ +void TYPVAL::SetValue(longlong n) +{ + char buf[24]; + PGLOBAL& g = Global; + int k = sprintf(buf, "%lld", n); + + if (k > Len) { + snprintf(g->Message, sizeof(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::SetValue(ulonglong n) +{ + char buf[24]; + PGLOBAL& g = Global; + int k = sprintf(buf, "%llu", n); + + if (k > Len) { + snprintf(g->Message, sizeof(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::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) { + snprintf(g->Message, sizeof(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::SetValue(char c) +{ + SetValue((int)c); + Null = false; +} // end of SetValue + +/***********************************************************************/ +/* STRING SetValue: get the character representation of a tiny int. */ +/***********************************************************************/ +void TYPVAL::SetValue(uchar c) +{ + SetValue((uint)c); + Null = false; +} // end of SetValue + +/***********************************************************************/ +/* STRING SetBinValue: fill string with chars extracted from a line. */ +/***********************************************************************/ +void TYPVAL::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::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::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::GetCharString(char *) +{ + return Strp; +} // end of GetCharString + +/***********************************************************************/ +/* STRING compare value with another Value. */ +/***********************************************************************/ +bool TYPVAL::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::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::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: + // snprintf(g->Message, sizeof(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::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::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::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(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(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)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(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) { + snprintf(g->Message, sizeof(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, <ime, (my_time_t) *timep); + TIME_to_localtime(tm, <ime); + 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(<ime, ptm); + ltime.time_type= MYSQL_TIMESTAMP_DATETIME; + uint error_code; + time_t t= TIME_to_timestamp(current_thd, <ime, &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::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::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::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 + 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 + 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 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: 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 + +/***********************************************************************/ +/* Specific DECIMAL class. */ +/***********************************************************************/ +class DllExport DECVAL: public TYPVAL { + 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 { + public: + // Constructors + DTVAL(PGLOBAL g, int n, int p, PCSZ fmt); + DTVAL(int n); + using TYPVAL::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() {} + + // 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..7f0efb72 --- /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 +#include +#include +//#include +#else // !_WIN32 +#if defined(UNIX) +#include +#include +#include +#include +#else // !UNIX +#include +#endif // !UNIX +#include +#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()) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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 + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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(); + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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: + snprintf(g->Message, sizeof(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))) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(g->Message), "(XHUGE)lseek64: %s (%lld)", strerror(errno), noff[id].Val); + printf("%s\n", g->Message); +// snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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); + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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)) { + snprintf(g->Message, sizeof(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..21a91653 --- /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: + snprintf(g->Message, sizeof(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 +#include +#include +#include +#include "zlib.h" +#include "zip.h" +#include "my_attribute.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#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;ifilled_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 (uBackReaduMaxBack) + 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 (uBackReaduMaxBack) + 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_posz_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;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = + *(((const char*)extrafield_global)+i); + + for (i=0;ici.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;ici.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 */ -- cgit v1.2.3