2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source path is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the path LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
23 #include <sys/types.h>
27 #include <folly/experimental/io/FsUtil.h>
28 #include <folly/json.h>
30 #include "hphp/runtime/ext/facts/autoload-db.h"
31 #include "hphp/runtime/ext/facts/file-facts.h"
32 #include "hphp/util/assertions.h"
33 #include "hphp/util/hash.h"
34 #include "hphp/util/logger.h"
35 #include "hphp/util/trace.h"
43 folly::fs::path path
, SQLite::OpenMode rwMode
, ::gid_t gid
, ::mode_t perms
)
44 : m_path
{std::move(path
)}, m_rwMode
{rwMode
}, m_gid
{gid
}, m_perms
{perms
} {
45 always_assert(m_path
.is_absolute());
47 // Coerce DB permissions into unix owner/group/other bits
50 "Coercing DB permission bits {} to {}\n",
52 (m_perms
| 0600) & 0666);
57 bool DBData::operator==(const DBData
& rhs
) const {
58 return m_path
== rhs
.m_path
&& m_rwMode
== rhs
.m_rwMode
&&
59 m_gid
== rhs
.m_gid
&& m_perms
== rhs
.m_perms
;
62 std::string
DBData::toString() const {
63 return folly::sformat("DBData({}, {}, {})", m_path
.native(), m_gid
, m_perms
);
66 size_t DBData::hash() const {
67 return folly::hash::hash_combine(
68 hash_string_cs(m_path
.native().c_str(), m_path
.native().size()),
69 std::hash
<gid_t
>{}(m_gid
),
70 std::hash
<mode_t
>{}(m_perms
));
76 * Create the given file if it doesn't exist, setting its group ownership and
77 * permissions along the way.
79 void setFilePerms(const folly::fs::path
& path
, ::gid_t gid
, ::mode_t perms
) {
81 3, "Creating {} with gid={} and perms={}\n", path
.native(), gid
, perms
);
82 int dbFd
= ::open(path
.native().c_str(), O_CREAT
, perms
);
84 FTRACE(1, "Could not open DB at {}: errno={}", path
.native(), errno
);
90 if (::fchown(dbFd
, -1, gid
) == -1) {
92 1, "Could not chown({}, -1, {}): errno={}", path
.native(), gid
, errno
);
94 if (::fchmod(dbFd
, perms
) == -1) {
95 FTRACE(1, "Could not chmod({}, {}): errno={}", path
.native(), perms
, errno
);
99 // Representation of inheritance kinds in the DB
101 // `extends`, `implements`, or `use`
102 const int kDeriveKindExtends
= 0;
103 const int kDeriveKindRequireExtends
= 1;
104 const int kDeriveKindRequireImplements
= 2;
106 constexpr int toDBEnum(DeriveKind kind
) {
108 case DeriveKind::Extends
:
109 return kDeriveKindExtends
;
110 case DeriveKind::RequireExtends
:
111 return kDeriveKindRequireExtends
;
112 case DeriveKind::RequireImplements
:
113 return kDeriveKindRequireImplements
;
118 void createSchema(SQLiteTxn
& txn
) {
119 // Basically copied wholesale from FlibAutoloadMapSQL.php in WWW.
124 txn
.exec("CREATE TABLE IF NOT EXISTS all_paths ("
125 " pathid INTEGER PRIMARY KEY,"
126 " path TEXT NOT NULL UNIQUE"
129 // Table storing data about Classes, Interfaces, Enums, and Traits
130 txn
.exec("CREATE TABLE IF NOT EXISTS type_details ("
131 " typeid INTEGER PRIMARY KEY,"
132 " name TEXT NOT NULL COLLATE NOCASE,"
133 " pathid INTEGER NOT NULL REFERENCES all_paths ON DELETE CASCADE,"
134 " kind_of TEXT NOT NULL,"
135 " flags INTEGER NOT NULL,"
136 " UNIQUE (pathid, name)"
142 "CREATE TABLE IF NOT EXISTS path_sha1sum ("
143 " pathid INTEGER NOT NULL UNIQUE REFERENCES all_paths ON DELETE CASCADE,"
144 " sha1sum TEXT NOT NULL"
147 txn
.exec("CREATE TABLE IF NOT EXISTS function_paths ("
148 " pathid INTEGER NOT NULL REFERENCES all_paths ON DELETE CASCADE,"
149 " function TEXT NOT NULL COLLATE NOCASE,"
150 " UNIQUE (pathid, function)"
153 txn
.exec("CREATE TABLE IF NOT EXISTS constant_paths ("
154 " pathid INTEGER NOT NULL REFERENCES all_paths ON DELETE CASCADE,"
155 " constant TEXT NOT NULL,"
156 " UNIQUE (pathid, constant)"
160 "CREATE TABLE IF NOT EXISTS derived_types ("
161 " derived_id INTEGER NOT NULL REFERENCES type_details ON DELETE CASCADE,"
162 " base_name TEXT NOT NULL COLLATE NOCASE,"
163 " kind INTEGER NOT NULL,"
164 " UNIQUE (derived_id, base_name, kind)"
167 txn
.exec("CREATE TABLE IF NOT EXISTS watchman ("
168 " id INTEGER PRIMARY KEY CHECK (id = 0),"
170 " mergebase TEXT NULL"
173 txn
.exec("CREATE TABLE IF NOT EXISTS type_attributes ("
174 " typeid INTEGER NOT NULL REFERENCES type_details ON DELETE CASCADE,"
175 " attribute_name TEXT NOT NULL,"
176 " attribute_position INTEGER NULL,"
177 " attribute_value TEXT NULL,"
178 " UNIQUE (typeid, attribute_name, attribute_position)"
182 void rebuildIndices(SQLiteTxn
& txn
) {
184 // Basically copied wholesale from FlibAutoloadMapSQL.php in WWW.
187 txn
.exec("CREATE INDEX IF NOT EXISTS type_details__name"
188 " ON type_details (name)");
189 txn
.exec("CREATE INDEX IF NOT EXISTS type_details__pathid"
190 " ON type_details (pathid)");
193 txn
.exec("CREATE INDEX IF NOT EXISTS function_paths__pathid"
194 " ON function_paths (pathid)");
195 txn
.exec("CREATE INDEX IF NOT EXISTS function_paths__function"
196 " ON function_paths (function)");
199 txn
.exec("CREATE INDEX IF NOT EXISTS constant_paths__pathid"
200 " ON constant_paths (pathid)");
201 txn
.exec("CREATE INDEX IF NOT EXISTS constant_paths__constant"
202 " ON constant_paths (constant)");
205 txn
.exec("CREATE INDEX IF NOT EXISTS derived_types__base_name"
206 " ON derived_types (base_name)");
207 txn
.exec("CREATE INDEX IF NOT EXISTS derived_types__derived_id"
208 " ON derived_types (derived_id)");
211 txn
.exec("CREATE INDEX IF NOT EXISTS "
212 "type_attributes__attribute_name__typeid__attribute_position"
213 " ON type_attributes (attribute_name, typeid, attribute_position)");
216 TypeKind
toTypeKind(const std::string_view kind
) {
217 if (kind
== kTypeKindClass
) {
218 return TypeKind::Class
;
219 } else if (kind
== kTypeKindInterface
) {
220 return TypeKind::Interface
;
221 } else if (kind
== kTypeKindEnum
) {
222 return TypeKind::Enum
;
223 } else if (kind
== kTypeKindTrait
) {
224 return TypeKind::Trait
;
225 } else if (kind
== kTypeKindTypeAlias
) {
226 return TypeKind::TypeAlias
;
228 return TypeKind::Unknown
;
232 std::string
getTransitiveDerivedTypesQueryStr(
233 TypeKindMask kinds
, DeriveKindMask deriveKinds
) {
234 auto typeKindWhereClause
= [&]() -> std::string
{
235 if (kinds
== kTypeKindAll
|| kinds
== 0) {
238 std::string clause
= "AND (name=@base OR kind_of IN (";
239 auto needsDelim
= false;
245 TypeKind::TypeAlias
}) {
246 if (kinds
& static_cast<int>(kind
)) {
253 clause
+= toString(kind
);
260 auto deriveKindWhereClause
= [&]() -> std::string
{
261 if (deriveKinds
== kDeriveKindAll
|| deriveKinds
== 0) {
264 bool needsDelim
= false;
265 std::string clause
= "AND derived_types.kind IN (";
266 for (auto deriveKind
:
267 {DeriveKind::Extends
,
268 DeriveKind::RequireExtends
,
269 DeriveKind::RequireImplements
}) {
270 if (deriveKinds
& static_cast<int>(deriveKind
)) {
276 clause
+= folly::sformat("{}", toDBEnum(deriveKind
));
282 return folly::sformat(
283 "WITH RECURSIVE subtypes(id) AS ("
284 " SELECT typeid FROM type_details WHERE name=@base"
285 " UNION SELECT derived_id FROM derived_types, type_details, subtypes"
286 " WHERE derived_types.base_name=type_details.name"
287 " AND type_details.typeid=subtypes.id"
291 " SELECT name, path, kind_of, flags FROM type_details"
292 " JOIN all_paths USING (pathid)"
293 " WHERE type_details.typeid IN (SELECT id FROM subtypes)"
297 deriveKindWhereClause
,
298 typeKindWhereClause
);
302 explicit PathStmts(SQLite
& db
)
303 : m_insert
{db
.prepare(
304 "INSERT OR IGNORE INTO all_paths (path) VALUES (@path)")}
305 , m_erase
{db
.prepare("DELETE FROM all_paths WHERE path = @path")}
306 , m_getAll
{db
.prepare("SELECT path, sha1sum FROM path_sha1sum"
307 " JOIN all_paths USING (pathid)")} {
315 struct Sha1HexStmts
{
316 explicit Sha1HexStmts(SQLite
& db
)
317 : m_insert
{db
.prepare("INSERT OR REPLACE INTO path_sha1sum VALUES ("
318 " (SELECT pathid FROM all_paths WHERE path=@path),"
321 , m_get
{db
.prepare("SELECT sha1sum FROM path_sha1sum"
322 " JOIN all_paths USING (pathid)"
323 " WHERE path = @path")} {
331 explicit TypeStmts(SQLite
& db
)
332 : m_insertDetails
{db
.prepare(
333 "INSERT OR IGNORE INTO type_details (pathid, name, kind_of, "
336 " (SELECT pathid FROM all_paths WHERE path=@path),"
341 , m_getTypePath
{db
.prepare("SELECT path FROM type_details"
342 " JOIN all_paths USING (pathid)"
343 " WHERE name=@type")}
344 , m_getPathTypes
{db
.prepare("SELECT name FROM type_details"
345 " JOIN all_paths USING (pathid)"
346 " WHERE path=@path")}
347 , m_getKindAndFlags
{db
.prepare("SELECT kind_of, flags FROM type_details"
348 " JOIN all_paths USING (pathid)"
351 , m_insertBaseType
{db
.prepare(
352 "INSERT OR IGNORE INTO derived_types (base_name, derived_id, kind)"
355 " (SELECT typeid FROM type_details JOIN all_paths USING (pathid)"
356 " WHERE name=@derived AND path=@path),"
359 , m_getBaseTypes
{db
.prepare("SELECT base_name FROM derived_types"
360 " JOIN type_details AS derived_type ON "
361 "(derived_type.typeid=derived_id)"
362 " JOIN all_paths USING (pathid)"
363 " WHERE derived_type.name = @derived"
365 " AND kind = @kind")}
366 , m_getDerivedTypes
{db
.prepare(
367 "SELECT path, derived_type.name FROM derived_types"
368 " JOIN type_details AS derived_type ON "
369 "(derived_type.typeid=derived_id)"
370 " JOIN all_paths USING (pathid)"
371 " WHERE base_name = @base"
372 " AND kind = @kind")}
373 , m_insertAttribute
{db
.prepare(
374 "INSERT OR IGNORE INTO type_attributes ("
377 " attribute_position,"
381 " (SELECT typeid FROM type_details JOIN all_paths USING (pathid)"
382 " WHERE name=@type AND path=@path),"
384 " @attribute_position,"
387 , m_getAttributes
{db
.prepare("SELECT DISTINCT attribute_name"
388 " FROM type_attributes"
389 " JOIN type_details USING (typeid)"
390 " JOIN all_paths USING (pathid)"
391 " WHERE name=@type AND path = @path")}
392 , m_getAttributeArgs
{db
.prepare("SELECT attribute_value"
393 " FROM type_attributes"
394 " JOIN type_details USING (typeid)"
395 " JOIN all_paths USING (pathid)"
396 " WHERE name = @type"
398 " AND attribute_name = @attribute_name")}
399 , m_getTypesWithAttribute
{db
.prepare(
400 "SELECT name, path from type_details"
401 " JOIN all_paths USING (pathid)"
403 " SELECT * FROM type_attributes"
404 " WHERE attribute_name = @attribute_name"
405 " AND type_attributes.typeid=type_details.typeid"
407 , m_getCorrectCase
{db
.prepare(
408 "SELECT name FROM type_details WHERE name=@name")}
409 , m_getAll
{db
.prepare("SELECT name, path from type_details JOIN "
410 "all_paths USING (pathid)")} {
413 SQLiteStmt m_insertDetails
;
414 SQLiteStmt m_getTypePath
;
415 SQLiteStmt m_getPathTypes
;
416 SQLiteStmt m_getKindAndFlags
;
417 SQLiteStmt m_insertBaseType
;
418 SQLiteStmt m_getBaseTypes
;
419 SQLiteStmt m_getDerivedTypes
;
420 SQLiteStmt m_insertAttribute
;
421 SQLiteStmt m_getAttributes
;
422 SQLiteStmt m_getAttributeArgs
;
423 SQLiteStmt m_getTypesWithAttribute
;
424 SQLiteStmt m_getCorrectCase
;
428 struct FunctionStmts
{
429 explicit FunctionStmts(SQLite
& db
)
430 : m_insert
{db
.prepare(
431 "INSERT OR IGNORE INTO function_paths (function, pathid) VALUES ("
433 " (SELECT pathid FROM all_paths WHERE path=@path)"
435 , m_getFunctionPath
{db
.prepare("SELECT path FROM function_paths"
436 " JOIN all_paths USING (pathid)"
437 " WHERE function=@function")}
438 , m_getPathFunctions
{db
.prepare("SELECT function FROM function_paths"
439 " JOIN all_paths USING (pathid)"
440 " WHERE path=@path")}
441 , m_getCorrectCase
{db
.prepare(
442 "SELECT function from function_paths where function=@function")}
443 , m_getAll
{db
.prepare("SELECT function, path FROM function_paths JOIN "
444 "all_paths USING (pathid)")} {
448 SQLiteStmt m_getFunctionPath
;
449 SQLiteStmt m_getPathFunctions
;
450 SQLiteStmt m_getCorrectCase
;
454 struct ConstantStmts
{
455 explicit ConstantStmts(SQLite
& db
)
456 : m_insert
{db
.prepare(
457 "INSERT OR IGNORE INTO constant_paths (constant, pathid) VALUES("
459 " (SELECT pathid FROM all_paths"
462 , m_getConstantPath
{db
.prepare("SELECT path FROM constant_paths"
463 " JOIN all_paths USING (pathid)"
464 " WHERE constant=@constant")}
465 , m_getPathConstants
{db
.prepare("SELECT constant FROM constant_paths"
466 " JOIN all_paths USING (pathid)"
467 " WHERE path=@path")}
468 , m_getAll
{db
.prepare("SELECT constant, path FROM constant_paths JOIN "
469 "all_paths USING (pathid)")} {
473 SQLiteStmt m_getConstantPath
;
474 SQLiteStmt m_getPathConstants
;
479 explicit ClockStmts(SQLite
& db
)
480 : m_insert
{db
.prepare(
481 "INSERT OR REPLACE INTO watchman (OID, clock, mergebase)"
482 " VALUES (0, @clock, @mergebase)")}
483 , m_get
{db
.prepare("SELECT clock, mergebase FROM watchman WHERE OID=0")} {
489 struct AutoloadDBImpl final
: public AutoloadDB
{
490 explicit AutoloadDBImpl(SQLite db
)
491 : m_db
{std::move(db
)}
493 , m_sha1HexStmts
{m_db
}
495 , m_functionStmts
{m_db
}
496 , m_constantStmts
{m_db
}
497 , m_clockStmts
{m_db
} {
500 AutoloadDBImpl(const AutoloadDBImpl
&) = delete;
501 AutoloadDBImpl(AutoloadDBImpl
&&) noexcept
= default;
502 AutoloadDBImpl
& operator=(const AutoloadDBImpl
&) = delete;
503 AutoloadDBImpl
& operator=(AutoloadDBImpl
&&) noexcept
= delete;
505 ~AutoloadDBImpl() override
= default;
507 static AutoloadDBImpl
get(const DBData
& dbData
) {
508 assertx(dbData
.m_path
.is_absolute());
511 return SQLite::connect(dbData
.m_path
.native(), dbData
.m_rwMode
);
512 } catch (SQLiteExc
& e
) {
513 throw std::runtime_error
{folly::sformat(
514 "Couldn't open or create native Facts DB at {}",
515 dbData
.m_path
.native())};
518 if (dbData
.m_rwMode
== SQLite::OpenMode::ReadWrite
) {
519 // If writable, ensure the DB has the correct owner and permissions.
520 setFilePerms(dbData
.m_path
, dbData
.m_gid
, dbData
.m_perms
);
522 folly::fs::path
{dbData
.m_path
} += "-shm",
526 folly::fs::path
{dbData
.m_path
} += "-wal",
530 if (!db
.isReadOnly()) {
532 db
.setJournalMode(SQLite::JournalMode::WAL
);
533 } catch (SQLiteExc
& e
) {
535 case SQLiteExc::Code::BUSY
:
536 // This happens if multiple connections attempt to set WAL mode at
537 // the same time. We only need one connection to succeed.
544 db
.setSynchronousLevel(SQLite::SynchronousLevel::OFF
);
546 auto txn
= db
.begin();
549 db
.setBusyTimeout(60'000);
551 FTRACE(3, "Connected to SQLite DB at {}.\n", dbData
.m_path
.native());
554 return AutoloadDBImpl
{std::move(db
)};
557 SQLiteTxn
begin() override
{
561 void insertPath(SQLiteTxn
& txn
, const folly::fs::path
& path
) override
{
562 assertx(path
.is_relative());
563 FTRACE(4, "Registering path {} in the DB\n", path
.native());
564 auto query
= txn
.query(m_pathStmts
.m_insert
);
565 query
.bindString("@path", path
.native());
566 FTRACE(5, "Running {}\n", query
.sql());
572 const folly::fs::path
& path
,
573 const std::optional
<std::string
>& sha1hex
) override
{
574 assertx(path
.is_relative());
575 auto query
= txn
.query(m_sha1HexStmts
.m_insert
);
576 query
.bindString("@path", path
.native());
578 query
.bindString("@sha1sum", *sha1hex
);
580 query
.bindNull("@sha1sum");
582 FTRACE(5, "Running {}\n", query
.sql());
586 std::string
getSha1Hex(SQLiteTxn
& txn
, const folly::fs::path
& path
) override
{
587 assertx(path
.is_relative());
588 auto query
= txn
.query(m_sha1HexStmts
.m_get
);
589 query
.bindString("@path", path
.native());
590 FTRACE(5, "Running {}\n", query
.sql());
592 return std::string
{query
.getString(0)};
595 void erasePath(SQLiteTxn
& txn
, const folly::fs::path
& path
) override
{
596 assertx(path
.is_relative());
597 auto query
= txn
.query(m_pathStmts
.m_erase
);
598 query
.bindString("@path", path
.native());
599 FTRACE(5, "Running {}\n", query
.sql());
605 std::string_view type
,
606 const folly::fs::path
& path
,
608 int flags
) override
{
609 assertx(path
.is_relative());
611 auto query
= txn
.query(m_typeStmts
.m_insertDetails
);
612 query
.bindString("@name", type
);
613 query
.bindString("@path", path
.native());
614 query
.bindString("@kind_of", toString(kind
));
615 query
.bindInt("@flags", flags
);
616 FTRACE(5, "Running {}\n", query
.sql());
621 std::vector
<folly::fs::path
>
622 getTypePath(SQLiteTxn
& txn
, std::string_view type
) override
{
623 auto query
= txn
.query(m_typeStmts
.m_getTypePath
);
624 query
.bindString("@type", type
);
625 std::vector
<folly::fs::path
> results
;
626 FTRACE(5, "Running {}\n", query
.sql());
627 for (query
.step(); query
.row(); query
.step()) {
628 results
.emplace_back(std::string
{query
.getString(0)});
633 std::vector
<std::string
>
634 getPathTypes(SQLiteTxn
& txn
, const folly::fs::path
& path
) override
{
635 assertx(path
.is_relative());
636 auto query
= txn
.query(m_typeStmts
.m_getPathTypes
);
637 query
.bindString("@path", path
.native());
638 std::vector
<std::string
> types
;
639 FTRACE(5, "Running {}\n", query
.sql());
640 for (query
.step(); query
.row(); query
.step()) {
641 types
.emplace_back(query
.getString(0));
646 std::pair
<TypeKind
, int> getKindAndFlags(
648 const std::string_view type
,
649 const folly::fs::path
& path
) override
{
650 auto query
= txn
.query(m_typeStmts
.m_getKindAndFlags
);
651 query
.bindString("@type", type
);
652 query
.bindString("@path", path
.native());
653 FTRACE(5, "Running {}\n", query
.sql());
654 for (query
.step(); query
.row(); query
.step()) {
655 return {toTypeKind(query
.getString(0)), query
.getInt(1)};
657 return {TypeKind::Unknown
, 0};
662 const folly::fs::path
& path
,
663 const std::string_view derived
,
665 const std::string_view base
) override
{
666 assertx(path
.is_relative());
667 auto query
= txn
.query(m_typeStmts
.m_insertBaseType
);
668 query
.bindString("@path", path
.native());
669 query
.bindString("@derived", derived
);
670 query
.bindInt("@kind", toDBEnum(kind
));
671 query
.bindString("@base", base
);
672 FTRACE(5, "Running {}\n", query
.sql());
676 std::vector
<std::string
> getBaseTypes(
678 const folly::fs::path
& path
,
679 const std::string_view derived
,
680 DeriveKind kind
) override
{
681 assertx(path
.is_relative());
682 auto query
= txn
.query(m_typeStmts
.m_getBaseTypes
);
683 query
.bindString("@derived", derived
);
684 query
.bindString("@path", path
.native());
685 query
.bindInt("@kind", toDBEnum(kind
));
686 std::vector
<std::string
> types
;
687 FTRACE(5, "Running {}\n", query
.sql());
688 for (query
.step(); query
.row(); query
.step()) {
689 types
.emplace_back(query
.getString(0));
694 std::vector
<std::pair
<folly::fs::path
, std::string
>> getDerivedTypes(
695 SQLiteTxn
& txn
, const std::string_view base
, DeriveKind kind
) override
{
696 auto query
= txn
.query(m_typeStmts
.m_getDerivedTypes
);
697 query
.bindString("@base", base
);
698 query
.bindInt("@kind", toDBEnum(kind
));
699 std::vector
<std::pair
<folly::fs::path
, std::string
>> edges
;
700 FTRACE(5, "Running {}\n", query
.sql());
701 for (query
.step(); query
.row(); query
.step()) {
703 {folly::fs::path
{std::string
{query
.getString(0)}},
704 std::string
{query
.getString(1)}});
709 SQLiteStmt
& getTransitiveDerivedTypesStmt(
710 TypeKindMask kinds
, DeriveKindMask deriveKinds
) {
711 auto it
= m_derivedTypeStmts
.find({kinds
, deriveKinds
});
712 if (it
== m_derivedTypeStmts
.end()) {
713 return m_derivedTypeStmts
715 {std::make_tuple(kinds
, deriveKinds
),
717 getTransitiveDerivedTypesQueryStr(kinds
, deriveKinds
))})
723 RowIter
<DerivedTypeInfo
> getTransitiveDerivedTypes(
725 const std::string_view baseType
,
726 TypeKindMask kinds
= kTypeKindAll
,
727 DeriveKindMask deriveKinds
= kDeriveKindAll
) override
{
728 auto query
= txn
.query(getTransitiveDerivedTypesStmt(kinds
, deriveKinds
));
729 query
.bindString("@base", baseType
);
730 FTRACE(5, "Running {}\n", query
.sql());
731 return RowIter
<DerivedTypeInfo
>{
732 std::move(query
), [](SQLiteQuery
& query
) -> DerivedTypeInfo
{
736 toTypeKind(query
.getString(2)),
741 void insertTypeAttribute(
743 const folly::fs::path
& path
,
744 const std::string_view type
,
745 const std::string_view attributeName
,
746 std::optional
<int> attributePosition
,
747 const folly::dynamic
* attributeValue
) override
{
749 std::string attrValueJson
;
750 auto query
= txn
.query(m_typeStmts
.m_insertAttribute
);
752 auto const attributeValueKey
= "@attribute_value";
753 if (attributeValue
) {
754 attrValueJson
= folly::toJson(*attributeValue
);
755 query
.bindString(attributeValueKey
, attrValueJson
);
757 query
.bindNull(attributeValueKey
);
760 auto const attributePositionKey
= "@attribute_position";
761 if (attributePosition
) {
762 query
.bindInt(attributePositionKey
, *attributePosition
);
764 query
.bindNull(attributePositionKey
);
767 query
.bindString("@type", type
);
768 query
.bindString("@path", path
.native());
769 query
.bindString("@attribute_name", attributeName
);
771 FTRACE(5, "Running {}\n", query
.sql());
775 void analyze() override
{
779 std::vector
<std::string
> getAttributesOfType(
781 const std::string_view type
,
782 const folly::fs::path
& path
) override
{
783 auto query
= txn
.query(m_typeStmts
.m_getAttributes
);
784 query
.bindString("@type", type
);
785 query
.bindString("@path", path
.native());
786 std::vector
<std::string
> results
;
787 FTRACE(5, "Running {}\n", query
.sql());
788 for (query
.step(); query
.row(); query
.step()) {
789 results
.emplace_back(query
.getString(0));
794 std::vector
<std::pair
<std::string
, folly::fs::path
>> getTypesWithAttribute(
795 SQLiteTxn
& txn
, const std::string_view attributeName
) override
{
796 auto query
= txn
.query(m_typeStmts
.m_getTypesWithAttribute
);
797 query
.bindString("@attribute_name", attributeName
);
798 std::vector
<std::pair
<std::string
, folly::fs::path
>> results
;
799 FTRACE(5, "Running {}\n", query
.sql());
800 for (query
.step(); query
.row(); query
.step()) {
801 results
.emplace_back(query
.getString(0), std::string
{query
.getString(1)});
806 std::vector
<folly::dynamic
> getAttributeArgs(
808 const std::string_view type
,
809 const std::string_view path
,
810 const std::string_view attributeName
) override
{
811 auto query
= txn
.query(m_typeStmts
.m_getAttributeArgs
);
812 query
.bindString("@type", type
);
813 query
.bindString("@path", path
);
814 query
.bindString("@attribute_name", attributeName
);
815 FTRACE(5, "Running {}\n", query
.sql());
816 std::vector
<folly::dynamic
> args
;
817 for (query
.step(); query
.row(); query
.step()) {
818 auto arg
= query
.getNullableString(0);
820 args
.push_back(folly::parseJson(*arg
));
827 getTypeCorrectCase(SQLiteTxn
& txn
, std::string_view type
) override
{
828 auto query
= txn
.query(m_typeStmts
.m_getCorrectCase
);
829 query
.bindString("@name", type
);
830 for (query
.step(); query
.row(); query
.step()) {
831 return std::string
{query
.getString(0)};
838 std::string_view function
,
839 const folly::fs::path
& path
) override
{
840 assertx(path
.is_relative());
841 auto query
= txn
.query(m_functionStmts
.m_insert
);
842 query
.bindString("@function", function
);
843 query
.bindString("@path", path
.native());
844 FTRACE(5, "Running {}\n", query
.sql());
848 std::vector
<folly::fs::path
>
849 getFunctionPath(SQLiteTxn
& txn
, std::string_view function
) override
{
850 auto query
= txn
.query(m_functionStmts
.m_getFunctionPath
);
851 query
.bindString("@function", function
);
852 FTRACE(5, "Running {}\n", query
.sql());
853 std::vector
<folly::fs::path
> results
;
854 for (query
.step(); query
.row(); query
.step()) {
855 results
.emplace_back(std::string
{query
.getString(0)});
860 std::vector
<std::string
>
861 getPathFunctions(SQLiteTxn
& txn
, const folly::fs::path
& path
) override
{
862 assertx(path
.is_relative());
863 auto query
= txn
.query(m_functionStmts
.m_getPathFunctions
);
864 query
.bindString("@path", path
.native());
865 std::vector
<std::string
> functions
;
866 FTRACE(5, "Running {}\n", query
.sql());
867 for (query
.step(); query
.row(); query
.step()) {
868 functions
.emplace_back(query
.getString(0));
874 getFunctionCorrectCase(SQLiteTxn
& txn
, std::string_view function
) override
{
875 auto query
= txn
.query(m_functionStmts
.m_getCorrectCase
);
876 query
.bindString("@function", function
);
877 for (query
.step(); query
.row(); query
.step()) {
878 return std::string
{query
.getString(0)};
885 std::string_view constant
,
886 const folly::fs::path
& path
) override
{
887 assertx(path
.is_relative());
888 auto query
= txn
.query(m_constantStmts
.m_insert
);
889 query
.bindString("@constant", constant
);
890 query
.bindString("@path", path
.native());
891 FTRACE(5, "Running {}\n", query
.sql());
895 std::vector
<folly::fs::path
>
896 getConstantPath(SQLiteTxn
& txn
, std::string_view constant
) override
{
897 auto query
= txn
.query(m_constantStmts
.m_getConstantPath
);
898 query
.bindString("@constant", constant
);
899 std::vector
<folly::fs::path
> results
;
900 FTRACE(5, "Running {}\n", query
.sql());
901 for (query
.step(); query
.row(); query
.step()) {
902 results
.emplace_back(std::string
{query
.getString(0)});
907 std::vector
<std::string
>
908 getPathConstants(SQLiteTxn
& txn
, const folly::fs::path
& path
) override
{
909 assertx(path
.is_relative());
910 auto query
= txn
.query(m_constantStmts
.m_getPathConstants
);
911 query
.bindString("@path", path
.native());
912 std::vector
<std::string
> constants
;
913 FTRACE(5, "Running {}\n", query
.sql());
914 for (query
.step(); query
.row(); query
.step()) {
915 constants
.emplace_back(query
.getString(0));
920 RowIter
<PathAndHash
> getAllPathsAndHashes(SQLiteTxn
& txn
) override
{
921 auto query
= txn
.query(m_pathStmts
.m_getAll
);
922 FTRACE(5, "Running {}\n", query
.sql());
923 return RowIter
<PathAndHash
>{
924 std::move(query
), [](SQLiteQuery
& q
) -> PathAndHash
{
925 return {std::string
{q
.getString(0)}, q
.getString(1)};
929 RowIter
<SymbolPath
> getAllTypePaths(SQLiteTxn
& txn
) override
{
930 auto query
= txn
.query(m_typeStmts
.m_getAll
);
931 FTRACE(5, "Running {}\n", query
.sql());
932 return RowIter
<SymbolPath
>{
933 std::move(query
), [](SQLiteQuery
& q
) -> SymbolPath
{
934 return {q
.getString(0), {std::string
{q
.getString(1)}}};
938 RowIter
<SymbolPath
> getAllFunctionPaths(SQLiteTxn
& txn
) override
{
939 auto query
= txn
.query(m_functionStmts
.m_getAll
);
940 FTRACE(5, "Running {}\n", query
.sql());
941 return RowIter
<SymbolPath
>{
942 std::move(query
), [](SQLiteQuery
& q
) -> SymbolPath
{
943 return {q
.getString(0), {std::string
{q
.getString(1)}}};
947 RowIter
<SymbolPath
> getAllConstantPaths(SQLiteTxn
& txn
) override
{
948 auto query
= txn
.query(m_constantStmts
.m_getAll
);
949 FTRACE(5, "Running {}\n", query
.sql());
950 return RowIter
<SymbolPath
>{
951 std::move(query
), [](SQLiteQuery
& q
) -> SymbolPath
{
952 return {q
.getString(0), {std::string
{q
.getString(1)}}};
956 void insertClock(SQLiteTxn
& txn
, std::string_view clock
) override
{
957 auto query
= txn
.query(m_clockStmts
.m_insert
);
958 query
.bindString("@clock", clock
);
959 FTRACE(5, "Running {}\n", query
.sql());
963 std::string
getClock(SQLiteTxn
& txn
) override
{
964 auto query
= txn
.query(m_clockStmts
.m_get
);
965 FTRACE(5, "Running {}\n", query
.sql());
970 return std::string
{query
.getString(0)};
974 PathStmts m_pathStmts
;
975 Sha1HexStmts m_sha1HexStmts
;
976 TypeStmts m_typeStmts
;
977 hphp_hash_map
<std::tuple
<TypeKindMask
, DeriveKindMask
>, SQLiteStmt
>
979 FunctionStmts m_functionStmts
;
980 ConstantStmts m_constantStmts
;
981 ClockStmts m_clockStmts
;
986 AutoloadDB::~AutoloadDB() = default;
988 THREAD_LOCAL(AutoloadDBThreadLocal
, t_adb
);
990 AutoloadDB
& getDB(const DBData
& dbData
) {
991 AutoloadDBThreadLocal
& dbVault
= *t_adb
.get();
992 auto& dbPtr
= dbVault
[{dbData
.m_path
.native(), dbData
.m_rwMode
}];
994 dbPtr
= std::make_unique
<AutoloadDBImpl
>(AutoloadDBImpl::get(dbData
));